@tsonic/emitter 0.0.67 → 0.0.68

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 (113) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/array.test.js +67 -3
  3. package/dist/array.test.js.map +1 -1
  4. package/dist/core/format/backend-ast/index.d.ts +1 -1
  5. package/dist/core/format/backend-ast/index.d.ts.map +1 -1
  6. package/dist/core/format/backend-ast/index.js.map +1 -1
  7. package/dist/core/format/backend-ast/printer.d.ts.map +1 -1
  8. package/dist/core/format/backend-ast/printer.js +5 -1
  9. package/dist/core/format/backend-ast/printer.js.map +1 -1
  10. package/dist/core/format/backend-ast/types.d.ts +6 -1
  11. package/dist/core/format/backend-ast/types.d.ts.map +1 -1
  12. package/dist/core/format/module-emitter/orchestrator.d.ts.map +1 -1
  13. package/dist/core/format/module-emitter/orchestrator.js +7 -0
  14. package/dist/core/format/module-emitter/orchestrator.js.map +1 -1
  15. package/dist/core/module-emitter.test.js +125 -0
  16. package/dist/core/module-emitter.test.js.map +1 -1
  17. package/dist/core/semantic/imports.d.ts.map +1 -1
  18. package/dist/core/semantic/imports.js +62 -4
  19. package/dist/core/semantic/imports.js.map +1 -1
  20. package/dist/core/semantic/imports.test.js +186 -0
  21. package/dist/core/semantic/imports.test.js.map +1 -1
  22. package/dist/core/semantic/module-map.d.ts.map +1 -1
  23. package/dist/core/semantic/module-map.js +6 -0
  24. package/dist/core/semantic/module-map.js.map +1 -1
  25. package/dist/core/semantic/module-map.test.js +52 -1
  26. package/dist/core/semantic/module-map.test.js.map +1 -1
  27. package/dist/core/semantic/mutable-storage.d.ts +10 -0
  28. package/dist/core/semantic/mutable-storage.d.ts.map +1 -0
  29. package/dist/core/semantic/mutable-storage.js +479 -0
  30. package/dist/core/semantic/mutable-storage.js.map +1 -0
  31. package/dist/core/semantic/type-resolution.d.ts.map +1 -1
  32. package/dist/core/semantic/type-resolution.js +14 -5
  33. package/dist/core/semantic/type-resolution.js.map +1 -1
  34. package/dist/core/semantic/type-resolution.test.js +2 -0
  35. package/dist/core/semantic/type-resolution.test.js.map +1 -1
  36. package/dist/core/semantic/unsafe.d.ts.map +1 -1
  37. package/dist/core/semantic/unsafe.js +4 -0
  38. package/dist/core/semantic/unsafe.js.map +1 -1
  39. package/dist/emitter-types/core.d.ts +10 -0
  40. package/dist/emitter-types/core.d.ts.map +1 -1
  41. package/dist/expression-emitter.d.ts.map +1 -1
  42. package/dist/expression-emitter.js +73 -3
  43. package/dist/expression-emitter.js.map +1 -1
  44. package/dist/expressions/access.d.ts +2 -2
  45. package/dist/expressions/access.d.ts.map +1 -1
  46. package/dist/expressions/access.js +16 -2
  47. package/dist/expressions/access.js.map +1 -1
  48. package/dist/expressions/calls/call-emitter.d.ts.map +1 -1
  49. package/dist/expressions/calls/call-emitter.js +1350 -122
  50. package/dist/expressions/calls/call-emitter.js.map +1 -1
  51. package/dist/expressions/collections.d.ts +3 -0
  52. package/dist/expressions/collections.d.ts.map +1 -1
  53. package/dist/expressions/collections.js +126 -43
  54. package/dist/expressions/collections.js.map +1 -1
  55. package/dist/expressions/functions.d.ts.map +1 -1
  56. package/dist/expressions/functions.js +126 -50
  57. package/dist/expressions/functions.js.map +1 -1
  58. package/dist/expressions/index.test.js +447 -0
  59. package/dist/expressions/index.test.js.map +1 -1
  60. package/dist/expressions/operators/assignment-emitter.d.ts.map +1 -1
  61. package/dist/expressions/operators/assignment-emitter.js +5 -1
  62. package/dist/expressions/operators/assignment-emitter.js.map +1 -1
  63. package/dist/expressions/parentheses.d.ts.map +1 -1
  64. package/dist/expressions/parentheses.js +4 -0
  65. package/dist/expressions/parentheses.js.map +1 -1
  66. package/dist/integration.test.js +343 -0
  67. package/dist/integration.test.js.map +1 -1
  68. package/dist/json-aot-generic.test.js +114 -0
  69. package/dist/json-aot-generic.test.js.map +1 -1
  70. package/dist/patterns.d.ts.map +1 -1
  71. package/dist/patterns.js +194 -0
  72. package/dist/patterns.js.map +1 -1
  73. package/dist/patterns.test.js +79 -0
  74. package/dist/patterns.test.js.map +1 -1
  75. package/dist/statements/classes/members/properties.d.ts.map +1 -1
  76. package/dist/statements/classes/members/properties.js +10 -3
  77. package/dist/statements/classes/members/properties.js.map +1 -1
  78. package/dist/statements/classes/members/static-readonly-properties.test.js +74 -1
  79. package/dist/statements/classes/members/static-readonly-properties.test.js.map +1 -1
  80. package/dist/statements/classes/properties.d.ts.map +1 -1
  81. package/dist/statements/classes/properties.js +4 -2
  82. package/dist/statements/classes/properties.js.map +1 -1
  83. package/dist/statements/control/conditionals/if-emitter.d.ts.map +1 -1
  84. package/dist/statements/control/conditionals/if-emitter.js +137 -0
  85. package/dist/statements/control/conditionals/if-emitter.js.map +1 -1
  86. package/dist/statements/control/loops.d.ts.map +1 -1
  87. package/dist/statements/control/loops.js +65 -3
  88. package/dist/statements/control/loops.js.map +1 -1
  89. package/dist/statements/declarations/classes.d.ts.map +1 -1
  90. package/dist/statements/declarations/classes.js +4 -1
  91. package/dist/statements/declarations/classes.js.map +1 -1
  92. package/dist/statements/declarations/interfaces-mutable-storage.test.d.ts +2 -0
  93. package/dist/statements/declarations/interfaces-mutable-storage.test.d.ts.map +1 -0
  94. package/dist/statements/declarations/interfaces-mutable-storage.test.js +84 -0
  95. package/dist/statements/declarations/interfaces-mutable-storage.test.js.map +1 -0
  96. package/dist/statements/declarations/interfaces.d.ts.map +1 -1
  97. package/dist/statements/declarations/interfaces.js +4 -1
  98. package/dist/statements/declarations/interfaces.js.map +1 -1
  99. package/dist/statements/declarations/variables.d.ts.map +1 -1
  100. package/dist/statements/declarations/variables.js +89 -2
  101. package/dist/statements/declarations/variables.js.map +1 -1
  102. package/dist/types/functions.d.ts.map +1 -1
  103. package/dist/types/functions.js +3 -1
  104. package/dist/types/functions.js.map +1 -1
  105. package/dist/types/references.d.ts.map +1 -1
  106. package/dist/types/references.js +19 -16
  107. package/dist/types/references.js.map +1 -1
  108. package/dist/types/references.test.js +17 -0
  109. package/dist/types/references.test.js.map +1 -1
  110. package/dist/types/unions.d.ts.map +1 -1
  111. package/dist/types/unions.js +41 -16
  112. package/dist/types/unions.js.map +1 -1
  113. package/package.json +2 -2
@@ -8,8 +8,10 @@ import { emitMemberAccess } from "../access.js";
8
8
  import { isLValue, getPassingModifierFromCast, isJsonSerializerCall, isGlobalJsonCall, isInstanceMemberAccess, shouldEmitFluentExtensionCall, getTypeNamespace, registerJsonAotType, needsIntCast, isPromiseChainMethod, isAsyncWrapperType, } from "./call-analysis.js";
9
9
  import { extractCalleeNameFromAst } from "../../core/format/backend-ast/utils.js";
10
10
  import { resolveImportPath } from "../../core/semantic/index.js";
11
+ import { containsTypeParameter } from "../../core/semantic/type-resolution.js";
12
+ import { allocateLocalName } from "../../core/format/local-names.js";
11
13
  /**
12
- * Wrap an expression AST with an optional argument modifier (ref/out/in/params).
14
+ * Wrap an expression AST with an optional argument modifier (ref/out/in).
13
15
  */
14
16
  const wrapArgModifier = (modifier, expr) => modifier
15
17
  ? { kind: "argumentModifierExpression", modifier, expression: expr }
@@ -25,6 +27,221 @@ const wrapIntCast = (needsCast, expr) => needsCast
25
27
  }
26
28
  : expr;
27
29
  const stripClrGenericArity = (typeName) => typeName.replace(/`\d+$/, "");
30
+ const nativeArrayMutationMembers = new Set([
31
+ "push",
32
+ "pop",
33
+ "shift",
34
+ "unshift",
35
+ "splice",
36
+ "sort",
37
+ "reverse",
38
+ "fill",
39
+ "copyWithin",
40
+ ]);
41
+ const returnsMutatedArrayMember = (memberName) => memberName === "sort" ||
42
+ memberName === "reverse" ||
43
+ memberName === "fill" ||
44
+ memberName === "copyWithin";
45
+ const createVarLocal = (name, initializer) => ({
46
+ kind: "localDeclarationStatement",
47
+ modifiers: [],
48
+ type: { kind: "varType" },
49
+ declarators: [{ name, initializer }],
50
+ });
51
+ const captureAssignableArrayTarget = (expr, context) => {
52
+ const [receiverAst, receiverContext] = emitExpressionAst(expr, context);
53
+ if (receiverAst.kind === "identifierExpression") {
54
+ return {
55
+ readExpression: receiverAst,
56
+ writeExpression: receiverAst,
57
+ setupStatements: [],
58
+ context: receiverContext,
59
+ };
60
+ }
61
+ if (receiverAst.kind === "memberAccessExpression") {
62
+ const objectTemp = allocateLocalName("__tsonic_arrayTarget", receiverContext);
63
+ const objectIdentifier = {
64
+ kind: "identifierExpression",
65
+ identifier: objectTemp.emittedName,
66
+ };
67
+ return {
68
+ readExpression: {
69
+ kind: "memberAccessExpression",
70
+ expression: objectIdentifier,
71
+ memberName: receiverAst.memberName,
72
+ },
73
+ writeExpression: {
74
+ kind: "memberAccessExpression",
75
+ expression: objectIdentifier,
76
+ memberName: receiverAst.memberName,
77
+ },
78
+ setupStatements: [
79
+ createVarLocal(objectTemp.emittedName, receiverAst.expression),
80
+ ],
81
+ context: objectTemp.context,
82
+ };
83
+ }
84
+ if (receiverAst.kind === "elementAccessExpression" &&
85
+ receiverAst.arguments.length === 1) {
86
+ const objectTemp = allocateLocalName("__tsonic_arrayTarget", receiverContext);
87
+ const indexTemp = allocateLocalName("__tsonic_arrayIndex", objectTemp.context);
88
+ const objectIdentifier = {
89
+ kind: "identifierExpression",
90
+ identifier: objectTemp.emittedName,
91
+ };
92
+ const indexIdentifier = {
93
+ kind: "identifierExpression",
94
+ identifier: indexTemp.emittedName,
95
+ };
96
+ return {
97
+ readExpression: {
98
+ kind: "elementAccessExpression",
99
+ expression: objectIdentifier,
100
+ arguments: [indexIdentifier],
101
+ },
102
+ writeExpression: {
103
+ kind: "elementAccessExpression",
104
+ expression: objectIdentifier,
105
+ arguments: [indexIdentifier],
106
+ },
107
+ setupStatements: [
108
+ createVarLocal(objectTemp.emittedName, receiverAst.expression),
109
+ createVarLocal(indexTemp.emittedName, receiverAst.arguments[0]),
110
+ ],
111
+ context: indexTemp.context,
112
+ };
113
+ }
114
+ return undefined;
115
+ };
116
+ const emitArrayMutationInteropCall = (expr, context) => {
117
+ if (expr.isOptional)
118
+ return undefined;
119
+ if (expr.callee.kind !== "memberAccess")
120
+ return undefined;
121
+ if (expr.callee.isComputed)
122
+ return undefined;
123
+ if (typeof expr.callee.property !== "string")
124
+ return undefined;
125
+ if (!nativeArrayMutationMembers.has(expr.callee.property))
126
+ return undefined;
127
+ if (!isLValue(expr.callee.object))
128
+ return undefined;
129
+ const binding = expr.callee.memberBinding;
130
+ if (!binding || binding.isExtensionMethod)
131
+ return undefined;
132
+ const receiverType = expr.callee.object.inferredType;
133
+ if (!receiverType || receiverType.kind !== "arrayType")
134
+ return undefined;
135
+ const captured = captureAssignableArrayTarget(expr.callee.object, context);
136
+ if (!captured)
137
+ return undefined;
138
+ let currentContext = captured.context;
139
+ const [elementTypeAst, elementTypeContext] = emitTypeAst(receiverType.elementType, currentContext);
140
+ currentContext = elementTypeContext;
141
+ const wrapperTemp = allocateLocalName("__tsonic_arrayWrapper", currentContext);
142
+ currentContext = wrapperTemp.context;
143
+ const resultTemp = allocateLocalName("__tsonic_arrayResult", currentContext);
144
+ currentContext = resultTemp.context;
145
+ const wrapperIdentifier = {
146
+ kind: "identifierExpression",
147
+ identifier: wrapperTemp.emittedName,
148
+ };
149
+ const resultIdentifier = {
150
+ kind: "identifierExpression",
151
+ identifier: resultTemp.emittedName,
152
+ };
153
+ const [argAsts, argContext] = emitCallArguments(expr.arguments, expr, currentContext);
154
+ currentContext = argContext;
155
+ const mutationCall = {
156
+ kind: "invocationExpression",
157
+ expression: {
158
+ kind: "memberAccessExpression",
159
+ expression: wrapperIdentifier,
160
+ memberName: binding.member,
161
+ },
162
+ arguments: argAsts,
163
+ };
164
+ const mutatedArrayAst = {
165
+ kind: "invocationExpression",
166
+ expression: {
167
+ kind: "memberAccessExpression",
168
+ expression: wrapperIdentifier,
169
+ memberName: "toArray",
170
+ },
171
+ arguments: [],
172
+ };
173
+ let returnExpression = resultIdentifier;
174
+ if (expr.callee.property === "splice") {
175
+ returnExpression = {
176
+ kind: "invocationExpression",
177
+ expression: {
178
+ kind: "memberAccessExpression",
179
+ expression: resultIdentifier,
180
+ memberName: "toArray",
181
+ },
182
+ arguments: [],
183
+ };
184
+ }
185
+ else if (returnsMutatedArrayMember(expr.callee.property)) {
186
+ returnExpression = mutatedArrayAst;
187
+ }
188
+ const returnType = expr.inferredType ?? receiverType;
189
+ const [returnTypeAst, returnTypeContext] = emitTypeAst(returnType, currentContext);
190
+ currentContext = returnTypeContext;
191
+ const lambdaAst = {
192
+ kind: "lambdaExpression",
193
+ isAsync: false,
194
+ parameters: [],
195
+ body: {
196
+ kind: "blockStatement",
197
+ statements: [
198
+ ...captured.setupStatements,
199
+ createVarLocal(wrapperTemp.emittedName, {
200
+ kind: "objectCreationExpression",
201
+ type: {
202
+ kind: "identifierType",
203
+ name: "global::Tsonic.JSRuntime.JSArray",
204
+ typeArguments: [elementTypeAst],
205
+ },
206
+ arguments: [captured.readExpression],
207
+ }),
208
+ createVarLocal(resultTemp.emittedName, mutationCall),
209
+ {
210
+ kind: "expressionStatement",
211
+ expression: {
212
+ kind: "assignmentExpression",
213
+ operatorToken: "=",
214
+ left: captured.writeExpression,
215
+ right: mutatedArrayAst,
216
+ },
217
+ },
218
+ {
219
+ kind: "returnStatement",
220
+ expression: returnExpression,
221
+ },
222
+ ],
223
+ },
224
+ };
225
+ const delegateCastAst = {
226
+ kind: "castExpression",
227
+ type: buildDelegateType([], returnTypeAst),
228
+ expression: {
229
+ kind: "parenthesizedExpression",
230
+ expression: lambdaAst,
231
+ },
232
+ };
233
+ return [
234
+ wrapIntCast(needsIntCast(expr, expr.callee.property), {
235
+ kind: "invocationExpression",
236
+ expression: {
237
+ kind: "parenthesizedExpression",
238
+ expression: delegateCastAst,
239
+ },
240
+ arguments: [],
241
+ }),
242
+ currentContext,
243
+ ];
244
+ };
28
245
  const emitArrayWrapperInteropCall = (expr, context) => {
29
246
  if (expr.isOptional)
30
247
  return undefined;
@@ -142,11 +359,74 @@ const callbackParameterCount = (callbackExpr) => {
142
359
  }
143
360
  return 1;
144
361
  };
362
+ const collectBlockReturnTypes = (block) => {
363
+ const collectFromStatement = (statement) => {
364
+ switch (statement.kind) {
365
+ case "returnStatement":
366
+ return statement.expression?.inferredType
367
+ ? [statement.expression.inferredType]
368
+ : [];
369
+ case "blockStatement":
370
+ return statement.statements.flatMap(collectFromStatement);
371
+ case "ifStatement":
372
+ return [
373
+ ...collectFromStatement(statement.thenStatement),
374
+ ...(statement.elseStatement
375
+ ? collectFromStatement(statement.elseStatement)
376
+ : []),
377
+ ];
378
+ case "whileStatement":
379
+ case "forStatement":
380
+ case "forOfStatement":
381
+ case "forInStatement":
382
+ return collectFromStatement(statement.body);
383
+ case "switchStatement":
384
+ return statement.cases.flatMap((switchCase) => switchCase.statements.flatMap(collectFromStatement));
385
+ case "tryStatement":
386
+ return [
387
+ ...statement.tryBlock.statements.flatMap(collectFromStatement),
388
+ ...(statement.catchClause
389
+ ? statement.catchClause.body.statements.flatMap(collectFromStatement)
390
+ : []),
391
+ ...(statement.finallyBlock
392
+ ? statement.finallyBlock.statements.flatMap(collectFromStatement)
393
+ : []),
394
+ ];
395
+ case "functionDeclaration":
396
+ case "classDeclaration":
397
+ case "interfaceDeclaration":
398
+ case "enumDeclaration":
399
+ case "typeAliasDeclaration":
400
+ return [];
401
+ default:
402
+ return [];
403
+ }
404
+ };
405
+ return block.statements.flatMap(collectFromStatement);
406
+ };
407
+ const getCallbackDelegateReturnType = (callbackExpr) => {
408
+ if ((callbackExpr.kind === "arrowFunction" ||
409
+ callbackExpr.kind === "functionExpression") &&
410
+ callbackExpr.body.kind === "blockStatement") {
411
+ const returnTypes = collectBlockReturnTypes(callbackExpr.body);
412
+ const concreteReturnTypes = returnTypes.filter((type) => !isVoidOrUnknownIrType(type));
413
+ if (concreteReturnTypes.length === 0) {
414
+ return undefined;
415
+ }
416
+ const deduped = concreteReturnTypes.filter((type, index, all) => all.findIndex((candidate) => stableIrTypeKey(candidate) === stableIrTypeKey(type)) === index);
417
+ if (deduped.length === 1) {
418
+ return deduped[0];
419
+ }
420
+ return {
421
+ kind: "unionType",
422
+ types: deduped,
423
+ };
424
+ }
425
+ return getCallbackReturnType(callbackExpr);
426
+ };
145
427
  const callbackReturnsAsyncWrapper = (callbackExpr) => {
146
- const callbackType = callbackExpr.inferredType;
147
- return callbackType?.kind === "functionType"
148
- ? isAsyncWrapperType(callbackType.returnType)
149
- : false;
428
+ const delegateReturnType = getCallbackDelegateReturnType(callbackExpr);
429
+ return delegateReturnType ? isAsyncWrapperType(delegateReturnType) : false;
150
430
  };
151
431
  const buildInvocation = (expression, args) => ({
152
432
  kind: "invocationExpression",
@@ -178,32 +458,763 @@ const buildDelegateType = (parameterTypes, returnType) => {
178
458
  typeArguments: parameterTypes,
179
459
  };
180
460
  }
181
- return {
182
- kind: "identifierType",
183
- name: "global::System.Func",
184
- typeArguments: [...parameterTypes, returnType],
185
- };
461
+ return {
462
+ kind: "identifierType",
463
+ name: "global::System.Func",
464
+ typeArguments: [...parameterTypes, returnType],
465
+ };
466
+ };
467
+ const isVoidOrUnknownIrType = (type) => type === undefined ||
468
+ type.kind === "voidType" ||
469
+ type.kind === "unknownType" ||
470
+ (type.kind === "primitiveType" && type.name === "undefined");
471
+ const getCallbackReturnType = (callbackExpr) => {
472
+ if (callbackExpr.kind === "arrowFunction" &&
473
+ callbackExpr.body.kind !== "blockStatement" &&
474
+ !isVoidOrUnknownIrType(callbackExpr.body.inferredType)) {
475
+ return callbackExpr.body.inferredType;
476
+ }
477
+ const declared = callbackExpr.inferredType?.kind === "functionType"
478
+ ? callbackExpr.inferredType.returnType
479
+ : undefined;
480
+ if (!isVoidOrUnknownIrType(declared)) {
481
+ return declared;
482
+ }
483
+ if (callbackExpr.kind === "arrowFunction" &&
484
+ callbackExpr.body.kind !== "blockStatement") {
485
+ return callbackExpr.body.inferredType;
486
+ }
487
+ return undefined;
488
+ };
489
+ const getFunctionValueSignature = (expr) => {
490
+ const calleeType = expr.callee.inferredType;
491
+ if (!calleeType || calleeType.kind !== "functionType")
492
+ return undefined;
493
+ if (expr.callee.kind === "identifier" && expr.callee.resolvedClrType) {
494
+ return undefined;
495
+ }
496
+ if (expr.callee.kind === "memberAccess" && expr.callee.memberBinding) {
497
+ return undefined;
498
+ }
499
+ return calleeType;
500
+ };
501
+ const emitFunctionValueCallArguments = (args, signature, expr, context) => {
502
+ let currentContext = context;
503
+ const argAsts = [];
504
+ const parameters = signature.parameters;
505
+ const extractTupleRestCandidates = (type) => {
506
+ if (!type)
507
+ return undefined;
508
+ if (type.kind === "tupleType") {
509
+ return [type.elementTypes];
510
+ }
511
+ if (type.kind !== "unionType") {
512
+ return undefined;
513
+ }
514
+ const candidates = [];
515
+ for (const member of type.types) {
516
+ if (!member || member.kind !== "tupleType") {
517
+ return undefined;
518
+ }
519
+ candidates.push(member.elementTypes);
520
+ }
521
+ return candidates;
522
+ };
523
+ const tryEmitTupleRestArguments = (startIndex, parameterType) => {
524
+ const remainingArgs = args.slice(startIndex);
525
+ if (remainingArgs.some((arg) => arg?.kind === "spread")) {
526
+ return undefined;
527
+ }
528
+ const tupleCandidates = extractTupleRestCandidates(parameterType);
529
+ if (!tupleCandidates || tupleCandidates.length === 0) {
530
+ return undefined;
531
+ }
532
+ const matchingCandidates = tupleCandidates.filter((candidate) => candidate.length === remainingArgs.length);
533
+ if (matchingCandidates.length !== 1) {
534
+ return undefined;
535
+ }
536
+ const tupleElements = matchingCandidates[0] ?? [];
537
+ const emittedArgs = [];
538
+ let tupleContext = currentContext;
539
+ for (let index = 0; index < remainingArgs.length; index++) {
540
+ const arg = remainingArgs[index];
541
+ const expectedType = tupleElements[index];
542
+ if (!arg)
543
+ continue;
544
+ const [argAst, argContext] = emitExpressionAst(arg, tupleContext, expectedType);
545
+ emittedArgs.push(argAst);
546
+ tupleContext = argContext;
547
+ }
548
+ return [emittedArgs, tupleContext];
549
+ };
550
+ for (let i = 0; i < parameters.length; i++) {
551
+ const parameter = parameters[i];
552
+ if (!parameter)
553
+ continue;
554
+ if (parameter.isRest) {
555
+ const tupleRestResult = tryEmitTupleRestArguments(i, parameter.type);
556
+ if (tupleRestResult) {
557
+ const [tupleArgs, tupleContext] = tupleRestResult;
558
+ argAsts.push(...tupleArgs);
559
+ currentContext = tupleContext;
560
+ break;
561
+ }
562
+ const spreadArg = args[i];
563
+ if (args.length === i + 1 && spreadArg && spreadArg.kind === "spread") {
564
+ const [spreadAst, spreadCtx] = emitExpressionAst(spreadArg.expression, currentContext);
565
+ argAsts.push(spreadAst);
566
+ currentContext = spreadCtx;
567
+ break;
568
+ }
569
+ const restElementType = parameter.type?.kind === "arrayType"
570
+ ? parameter.type.elementType
571
+ : undefined;
572
+ let elementTypeAst = {
573
+ kind: "identifierType",
574
+ name: "object",
575
+ };
576
+ if (restElementType) {
577
+ const [emittedType, typeCtx] = emitTypeAst(restElementType, currentContext);
578
+ elementTypeAst = emittedType;
579
+ currentContext = typeCtx;
580
+ }
581
+ const restItems = [];
582
+ for (let j = i; j < args.length; j++) {
583
+ const arg = args[j];
584
+ if (!arg)
585
+ continue;
586
+ if (arg.kind === "spread") {
587
+ const [spreadAst, spreadCtx] = emitExpressionAst(arg.expression, currentContext);
588
+ argAsts.push(spreadAst);
589
+ currentContext = spreadCtx;
590
+ return [argAsts, currentContext];
591
+ }
592
+ const [argAst, argCtx] = emitExpressionAst(arg, currentContext, restElementType);
593
+ restItems.push(argAst);
594
+ currentContext = argCtx;
595
+ }
596
+ argAsts.push({
597
+ kind: "arrayCreationExpression",
598
+ elementType: elementTypeAst,
599
+ initializer: restItems,
600
+ });
601
+ break;
602
+ }
603
+ const arg = args[i];
604
+ if (arg) {
605
+ const [argAst, argCtx] = emitExpressionAst(arg, currentContext, parameter.type);
606
+ const modifier = expr.argumentPassing?.[i] &&
607
+ expr.argumentPassing[i] !== "value" &&
608
+ isLValue(arg)
609
+ ? expr.argumentPassing[i]
610
+ : undefined;
611
+ argAsts.push(wrapArgModifier(modifier, argAst));
612
+ currentContext = argCtx;
613
+ continue;
614
+ }
615
+ if (parameter.isOptional || parameter.initializer) {
616
+ let defaultType;
617
+ if (parameter.type) {
618
+ const [emittedType, typeCtx] = emitTypeAst(parameter.type, currentContext);
619
+ currentContext = typeCtx;
620
+ defaultType =
621
+ parameter.isOptional || parameter.initializer
622
+ ? emittedType.kind === "nullableType"
623
+ ? emittedType
624
+ : { kind: "nullableType", underlyingType: emittedType }
625
+ : emittedType;
626
+ }
627
+ argAsts.push({ kind: "defaultExpression", type: defaultType });
628
+ }
629
+ }
630
+ return [argAsts, currentContext];
631
+ };
632
+ const isArrayLikeIrType = (type) => {
633
+ if (!type)
634
+ return false;
635
+ if (type.kind === "arrayType" || type.kind === "tupleType") {
636
+ return true;
637
+ }
638
+ if (type.kind === "unionType") {
639
+ return type.types.every((member) => isArrayLikeIrType(member));
640
+ }
641
+ if (type.kind !== "referenceType") {
642
+ return false;
643
+ }
644
+ const simpleName = type.name.split(".").pop() ?? type.name;
645
+ return (simpleName === "Array" ||
646
+ simpleName === "ReadonlyArray" ||
647
+ simpleName === "JSArray" ||
648
+ simpleName === "Iterable" ||
649
+ simpleName === "IterableIterator" ||
650
+ simpleName === "IEnumerable" ||
651
+ simpleName === "IReadOnlyList" ||
652
+ simpleName === "List");
653
+ };
654
+ const detectRestParameterInfo = (args, parameterTypes) => {
655
+ if (parameterTypes.length === 0) {
656
+ return undefined;
657
+ }
658
+ const index = parameterTypes.length - 1;
659
+ const lastParamType = parameterTypes[index];
660
+ if (!lastParamType || lastParamType.kind !== "arrayType") {
661
+ return undefined;
662
+ }
663
+ if (args.length > parameterTypes.length) {
664
+ return {
665
+ index,
666
+ arrayType: lastParamType,
667
+ elementType: lastParamType.elementType,
668
+ };
669
+ }
670
+ const restArgs = args.slice(index);
671
+ if (restArgs.some((arg) => arg?.kind === "spread")) {
672
+ return {
673
+ index,
674
+ arrayType: lastParamType,
675
+ elementType: lastParamType.elementType,
676
+ };
677
+ }
678
+ const lastArg = args[index];
679
+ if (!lastArg) {
680
+ return undefined;
681
+ }
682
+ const lastArgType = lastArg.kind === "spread"
683
+ ? lastArg.expression.inferredType
684
+ : lastArg.inferredType;
685
+ if (!isArrayLikeIrType(lastArgType)) {
686
+ return {
687
+ index,
688
+ arrayType: lastParamType,
689
+ elementType: lastParamType.elementType,
690
+ };
691
+ }
692
+ return undefined;
693
+ };
694
+ const emitFlattenedRestArguments = (restArgs, restElementType, context) => {
695
+ let currentContext = context;
696
+ const [elementTypeAst, typeContext] = emitTypeAst(restElementType, currentContext);
697
+ currentContext = typeContext;
698
+ const segments = [];
699
+ let inlineElements = [];
700
+ const flushInlineElements = () => {
701
+ if (inlineElements.length === 0)
702
+ return;
703
+ segments.push({
704
+ kind: "arrayCreationExpression",
705
+ elementType: elementTypeAst,
706
+ initializer: inlineElements,
707
+ });
708
+ inlineElements = [];
709
+ };
710
+ for (const arg of restArgs) {
711
+ if (!arg)
712
+ continue;
713
+ if (arg.kind === "spread") {
714
+ flushInlineElements();
715
+ const [spreadAst, spreadContext] = emitExpressionAst(arg.expression, currentContext);
716
+ segments.push(spreadAst);
717
+ currentContext = spreadContext;
718
+ continue;
719
+ }
720
+ const [argAst, argContext] = emitExpressionAst(arg, currentContext, restElementType);
721
+ inlineElements.push(argAst);
722
+ currentContext = argContext;
723
+ }
724
+ flushInlineElements();
725
+ if (segments.length === 0) {
726
+ return [
727
+ [
728
+ {
729
+ kind: "invocationExpression",
730
+ expression: {
731
+ kind: "identifierExpression",
732
+ identifier: "global::System.Array.Empty",
733
+ },
734
+ typeArguments: [elementTypeAst],
735
+ arguments: [],
736
+ },
737
+ ],
738
+ currentContext,
739
+ ];
740
+ }
741
+ let concatAst = segments[0];
742
+ for (let index = 1; index < segments.length; index++) {
743
+ concatAst = {
744
+ kind: "invocationExpression",
745
+ expression: {
746
+ kind: "identifierExpression",
747
+ identifier: "global::System.Linq.Enumerable.Concat",
748
+ },
749
+ arguments: [concatAst, segments[index]],
750
+ };
751
+ }
752
+ return [
753
+ [
754
+ {
755
+ kind: "invocationExpression",
756
+ expression: {
757
+ kind: "identifierExpression",
758
+ identifier: "global::System.Linq.Enumerable.ToArray",
759
+ },
760
+ arguments: [concatAst],
761
+ },
762
+ ],
763
+ currentContext,
764
+ ];
765
+ };
766
+ const stableIrTypeKey = (type) => JSON.stringify(type);
767
+ const unwrapAsyncWrapperIrType = (type) => {
768
+ if (type.kind !== "referenceType")
769
+ return undefined;
770
+ if (!type.typeArguments || type.typeArguments.length !== 1)
771
+ return undefined;
772
+ const inner = type.typeArguments[0];
773
+ if (!inner)
774
+ return undefined;
775
+ const simpleName = type.name.split(".").pop() ?? type.name;
776
+ const clrName = type.resolvedClrType ?? type.name;
777
+ const isAsyncWrapper = simpleName === "Promise" ||
778
+ simpleName === "PromiseLike" ||
779
+ simpleName === "Task_1" ||
780
+ simpleName === "Task`1" ||
781
+ simpleName === "ValueTask_1" ||
782
+ simpleName === "ValueTask`1" ||
783
+ clrName === "System.Threading.Tasks.Task" ||
784
+ clrName === "System.Threading.Tasks.ValueTask" ||
785
+ clrName.startsWith("System.Threading.Tasks.Task`1") ||
786
+ clrName.startsWith("System.Threading.Tasks.ValueTask`1");
787
+ return isAsyncWrapper ? inner : undefined;
788
+ };
789
+ const isAsyncWrapperIrTypeLike = (type) => {
790
+ if (type.kind !== "referenceType")
791
+ return false;
792
+ const simpleName = type.name.split(".").pop() ?? type.name;
793
+ const clrName = type.resolvedClrType ?? type.name;
794
+ return (simpleName === "Promise" ||
795
+ simpleName === "PromiseLike" ||
796
+ simpleName === "Task" ||
797
+ simpleName === "Task_1" ||
798
+ simpleName === "Task`1" ||
799
+ simpleName === "ValueTask" ||
800
+ simpleName === "ValueTask_1" ||
801
+ simpleName === "ValueTask`1" ||
802
+ clrName === "System.Threading.Tasks.Task" ||
803
+ clrName === "System.Threading.Tasks.ValueTask" ||
804
+ clrName.startsWith("System.Threading.Tasks.Task`1") ||
805
+ clrName.startsWith("System.Threading.Tasks.ValueTask`1"));
806
+ };
807
+ const containsPromiseChainArtifact = (type) => {
808
+ if (!type)
809
+ return false;
810
+ if (isAsyncWrapperIrTypeLike(type)) {
811
+ return true;
812
+ }
813
+ if (type.kind === "unionType" || type.kind === "intersectionType") {
814
+ return type.types.some((member) => !!member && containsPromiseChainArtifact(member));
815
+ }
816
+ return false;
817
+ };
818
+ const normalizePromiseChainResultIrType = (type) => {
819
+ if (!type)
820
+ return undefined;
821
+ const asyncInner = unwrapAsyncWrapperIrType(type);
822
+ if (asyncInner) {
823
+ return normalizePromiseChainResultIrType(asyncInner);
824
+ }
825
+ if (type.kind === "unionType") {
826
+ const normalizedTypes = [];
827
+ const seen = new Set();
828
+ for (const member of type.types) {
829
+ if (!member)
830
+ continue;
831
+ const normalized = normalizePromiseChainResultIrType(member);
832
+ if (!normalized)
833
+ continue;
834
+ const key = stableIrTypeKey(normalized);
835
+ if (seen.has(key))
836
+ continue;
837
+ seen.add(key);
838
+ normalizedTypes.push(normalized);
839
+ }
840
+ if (normalizedTypes.length === 0)
841
+ return undefined;
842
+ if (normalizedTypes.length === 1)
843
+ return normalizedTypes[0];
844
+ return {
845
+ kind: "unionType",
846
+ types: normalizedTypes,
847
+ };
848
+ }
849
+ return type;
850
+ };
851
+ const mergePromiseChainResultIrTypes = (...types) => {
852
+ const merged = [];
853
+ const seen = new Set();
854
+ for (const type of types) {
855
+ const normalized = normalizePromiseChainResultIrType(type);
856
+ if (!normalized)
857
+ continue;
858
+ if (normalized.kind === "unionType") {
859
+ for (const member of normalized.types) {
860
+ if (!member)
861
+ continue;
862
+ const key = stableIrTypeKey(member);
863
+ if (seen.has(key))
864
+ continue;
865
+ seen.add(key);
866
+ merged.push(member);
867
+ }
868
+ continue;
869
+ }
870
+ const key = stableIrTypeKey(normalized);
871
+ if (seen.has(key))
872
+ continue;
873
+ seen.add(key);
874
+ merged.push(normalized);
875
+ }
876
+ if (merged.length === 0)
877
+ return undefined;
878
+ if (merged.length === 1)
879
+ return merged[0];
880
+ return {
881
+ kind: "unionType",
882
+ types: merged,
883
+ };
884
+ };
885
+ const buildTaskTypeAst = (resultType) => resultType
886
+ ? {
887
+ kind: "identifierType",
888
+ name: "global::System.Threading.Tasks.Task",
889
+ typeArguments: [resultType],
890
+ }
891
+ : {
892
+ kind: "identifierType",
893
+ name: "global::System.Threading.Tasks.Task",
894
+ };
895
+ const buildTaskRunInvocation = (outputTaskType, body, isAsync) => {
896
+ const resultType = getTaskResultType(outputTaskType);
897
+ return {
898
+ kind: "invocationExpression",
899
+ expression: {
900
+ kind: "memberAccessExpression",
901
+ expression: {
902
+ kind: "identifierExpression",
903
+ identifier: "global::System.Threading.Tasks.Task",
904
+ },
905
+ memberName: "Run",
906
+ },
907
+ arguments: [
908
+ {
909
+ kind: "lambdaExpression",
910
+ isAsync,
911
+ parameters: [],
912
+ body,
913
+ },
914
+ ],
915
+ typeArguments: resultType ? [resultType] : undefined,
916
+ };
917
+ };
918
+ const buildCompletedTaskAst = () => ({
919
+ kind: "memberAccessExpression",
920
+ expression: {
921
+ kind: "identifierExpression",
922
+ identifier: "global::System.Threading.Tasks.Task",
923
+ },
924
+ memberName: "CompletedTask",
925
+ });
926
+ const buildPromiseRejectedExceptionAst = (reasonAst) => {
927
+ const reasonExpr = reasonAst ??
928
+ {
929
+ kind: "literalExpression",
930
+ text: "null",
931
+ };
932
+ return {
933
+ kind: "binaryExpression",
934
+ operatorToken: "??",
935
+ left: {
936
+ kind: "asExpression",
937
+ expression: reasonExpr,
938
+ type: {
939
+ kind: "identifierType",
940
+ name: "global::System.Exception",
941
+ },
942
+ },
943
+ right: {
944
+ kind: "objectCreationExpression",
945
+ type: {
946
+ kind: "identifierType",
947
+ name: "global::System.Exception",
948
+ },
949
+ arguments: [
950
+ {
951
+ kind: "binaryExpression",
952
+ operatorToken: "??",
953
+ left: {
954
+ kind: "invocationExpression",
955
+ expression: {
956
+ kind: "conditionalMemberAccessExpression",
957
+ expression: reasonExpr,
958
+ memberName: "ToString",
959
+ },
960
+ arguments: [],
961
+ },
962
+ right: {
963
+ kind: "literalExpression",
964
+ text: '"Promise rejected"',
965
+ },
966
+ },
967
+ ],
968
+ },
969
+ };
970
+ };
971
+ const getPromiseStaticMethod = (expr) => {
972
+ if (expr.callee.kind !== "memberAccess")
973
+ return undefined;
974
+ if (expr.callee.isComputed)
975
+ return undefined;
976
+ if (typeof expr.callee.property !== "string")
977
+ return undefined;
978
+ if (expr.callee.object.kind !== "identifier")
979
+ return undefined;
980
+ const objectName = expr.callee.object.originalName ?? expr.callee.object.name;
981
+ const simpleObjectName = objectName.split(".").pop() ?? objectName;
982
+ if (simpleObjectName !== "Promise")
983
+ return undefined;
984
+ switch (expr.callee.property) {
985
+ case "resolve":
986
+ case "reject":
987
+ case "all":
988
+ case "race":
989
+ return expr.callee.property;
990
+ default:
991
+ return undefined;
992
+ }
993
+ };
994
+ const getSequenceElementIrType = (type) => {
995
+ if (!type)
996
+ return undefined;
997
+ if (type.kind === "arrayType")
998
+ return type.elementType;
999
+ if (type.kind === "tupleType") {
1000
+ if (type.elementTypes.length === 0)
1001
+ return undefined;
1002
+ if (type.elementTypes.length === 1)
1003
+ return type.elementTypes[0];
1004
+ return { kind: "unionType", types: type.elementTypes };
1005
+ }
1006
+ if (type.kind === "referenceType" &&
1007
+ type.typeArguments &&
1008
+ type.typeArguments.length > 0) {
1009
+ const simpleName = type.name.split(".").pop() ?? type.name;
1010
+ switch (simpleName) {
1011
+ case "Array":
1012
+ case "ReadonlyArray":
1013
+ case "Iterable":
1014
+ case "IterableIterator":
1015
+ case "IEnumerable":
1016
+ case "IReadOnlyList":
1017
+ case "List":
1018
+ case "Set":
1019
+ case "ReadonlySet":
1020
+ case "JSArray":
1021
+ return type.typeArguments[0];
1022
+ default:
1023
+ return undefined;
1024
+ }
1025
+ }
1026
+ return undefined;
1027
+ };
1028
+ const isValueTaskLikeIrType = (type) => {
1029
+ if (!type || type.kind !== "referenceType")
1030
+ return false;
1031
+ const simpleName = type.name.split(".").pop() ?? type.name;
1032
+ const clrName = type.resolvedClrType ?? type.name;
1033
+ return (simpleName === "ValueTask" ||
1034
+ simpleName === "ValueTask_1" ||
1035
+ simpleName === "ValueTask`1" ||
1036
+ clrName === "System.Threading.Tasks.ValueTask" ||
1037
+ clrName.startsWith("System.Threading.Tasks.ValueTask`1"));
1038
+ };
1039
+ const emitPromiseNormalizedTaskAst = (valueAst, valueType, resultTypeAst, context) => {
1040
+ let currentContext = context;
1041
+ const asyncInner = valueType
1042
+ ? unwrapAsyncWrapperIrType(valueType)
1043
+ : undefined;
1044
+ if (asyncInner) {
1045
+ if (isValueTaskLikeIrType(valueType)) {
1046
+ return [
1047
+ {
1048
+ kind: "invocationExpression",
1049
+ expression: {
1050
+ kind: "memberAccessExpression",
1051
+ expression: valueAst,
1052
+ memberName: "AsTask",
1053
+ },
1054
+ arguments: [],
1055
+ },
1056
+ currentContext,
1057
+ ];
1058
+ }
1059
+ return [valueAst, currentContext];
1060
+ }
1061
+ if (valueType?.kind === "unionType") {
1062
+ const arms = [];
1063
+ for (let index = 0; index < valueType.types.length; index++) {
1064
+ const memberType = valueType.types[index];
1065
+ if (!memberType)
1066
+ continue;
1067
+ const [memberTypeAst, memberTypeContext] = emitTypeAst(memberType, currentContext);
1068
+ currentContext = memberTypeContext;
1069
+ const memberName = `__tsonic_promise_value_${index}`;
1070
+ const [normalizedArm, normalizedContext] = emitPromiseNormalizedTaskAst({
1071
+ kind: "identifierExpression",
1072
+ identifier: memberName,
1073
+ }, memberType, resultTypeAst, currentContext);
1074
+ currentContext = normalizedContext;
1075
+ arms.push({
1076
+ kind: "lambdaExpression",
1077
+ isAsync: false,
1078
+ parameters: [{ name: memberName, type: memberTypeAst }],
1079
+ body: normalizedArm,
1080
+ });
1081
+ }
1082
+ return [
1083
+ {
1084
+ kind: "invocationExpression",
1085
+ expression: {
1086
+ kind: "memberAccessExpression",
1087
+ expression: valueAst,
1088
+ memberName: "Match",
1089
+ },
1090
+ arguments: arms,
1091
+ },
1092
+ currentContext,
1093
+ ];
1094
+ }
1095
+ if (!resultTypeAst) {
1096
+ return [buildCompletedTaskAst(), currentContext];
1097
+ }
1098
+ return [
1099
+ {
1100
+ kind: "invocationExpression",
1101
+ expression: {
1102
+ kind: "memberAccessExpression",
1103
+ expression: {
1104
+ kind: "identifierExpression",
1105
+ identifier: "global::System.Threading.Tasks.Task",
1106
+ },
1107
+ memberName: "FromResult",
1108
+ },
1109
+ typeArguments: [resultTypeAst],
1110
+ arguments: [valueAst],
1111
+ },
1112
+ currentContext,
1113
+ ];
186
1114
  };
187
- const isVoidOrUnknownIrType = (type) => type === undefined ||
188
- type.kind === "voidType" ||
189
- type.kind === "unknownType" ||
190
- (type.kind === "primitiveType" && type.name === "undefined");
191
- const getCallbackReturnType = (callbackExpr) => {
192
- const declared = callbackExpr.inferredType?.kind === "functionType"
193
- ? callbackExpr.inferredType.returnType
194
- : undefined;
195
- if (!isVoidOrUnknownIrType(declared)) {
196
- return declared;
1115
+ const emitPromiseStaticCall = (expr, context) => {
1116
+ const method = getPromiseStaticMethod(expr);
1117
+ if (!method)
1118
+ return null;
1119
+ let currentContext = context;
1120
+ const [outputTaskType, outputTaskContext] = emitTypeAst(expr.inferredType ?? {
1121
+ kind: "referenceType",
1122
+ name: "Promise",
1123
+ typeArguments: [{ kind: "referenceType", name: "object" }],
1124
+ }, currentContext);
1125
+ currentContext = outputTaskContext;
1126
+ const outputResultType = getTaskResultType(outputTaskType);
1127
+ if (method === "resolve") {
1128
+ const argument = expr.arguments[0];
1129
+ if (!argument) {
1130
+ return [buildCompletedTaskAst(), currentContext];
1131
+ }
1132
+ const [valueAst, valueContext] = emitExpressionAst(argument, currentContext, argument.inferredType);
1133
+ currentContext = valueContext;
1134
+ return emitPromiseNormalizedTaskAst(valueAst, argument.inferredType, outputResultType, currentContext);
197
1135
  }
198
- if (callbackExpr.kind === "arrowFunction" &&
199
- callbackExpr.body.kind !== "blockStatement") {
200
- return callbackExpr.body.inferredType;
1136
+ if (method === "reject") {
1137
+ const reason = expr.arguments[0];
1138
+ let reasonAst;
1139
+ if (reason) {
1140
+ [reasonAst, currentContext] = emitExpressionAst(reason, currentContext, reason.inferredType);
1141
+ }
1142
+ const exceptionAst = buildPromiseRejectedExceptionAst(reasonAst);
1143
+ return [
1144
+ {
1145
+ kind: "invocationExpression",
1146
+ expression: {
1147
+ kind: "memberAccessExpression",
1148
+ expression: {
1149
+ kind: "identifierExpression",
1150
+ identifier: "global::System.Threading.Tasks.Task",
1151
+ },
1152
+ memberName: "FromException",
1153
+ },
1154
+ typeArguments: outputResultType ? [outputResultType] : undefined,
1155
+ arguments: [exceptionAst],
1156
+ },
1157
+ currentContext,
1158
+ ];
201
1159
  }
202
- return undefined;
203
- };
204
- const buildPromiseChainTaskRun = (outputTaskType, body) => {
205
- const resultType = getTaskResultType(outputTaskType);
206
- return {
1160
+ const valuesArg = expr.arguments[0];
1161
+ if (!valuesArg)
1162
+ return null;
1163
+ const [valuesAst, valuesContext] = emitExpressionAst(valuesArg, currentContext, valuesArg.inferredType);
1164
+ currentContext = valuesContext;
1165
+ const inputElementType = getSequenceElementIrType(valuesArg.inferredType);
1166
+ const resultElementTypeAst = outputResultType?.kind === "arrayType"
1167
+ ? outputResultType.elementType
1168
+ : outputResultType;
1169
+ let normalizedValuesAst = valuesAst;
1170
+ if (inputElementType) {
1171
+ const [inputElementTypeAst, inputElementContext] = emitTypeAst(inputElementType, currentContext);
1172
+ currentContext = inputElementContext;
1173
+ const [normalizedTaskAst, normalizedTaskContext] = emitPromiseNormalizedTaskAst({
1174
+ kind: "identifierExpression",
1175
+ identifier: "__tsonic_promise_item",
1176
+ }, inputElementType, resultElementTypeAst, currentContext);
1177
+ currentContext = normalizedTaskContext;
1178
+ normalizedValuesAst = {
1179
+ kind: "invocationExpression",
1180
+ expression: {
1181
+ kind: "identifierExpression",
1182
+ identifier: "global::System.Linq.Enumerable.Select",
1183
+ },
1184
+ arguments: [
1185
+ valuesAst,
1186
+ {
1187
+ kind: "lambdaExpression",
1188
+ isAsync: false,
1189
+ parameters: [
1190
+ {
1191
+ name: "__tsonic_promise_item",
1192
+ type: inputElementTypeAst,
1193
+ },
1194
+ ],
1195
+ body: normalizedTaskAst,
1196
+ },
1197
+ ],
1198
+ };
1199
+ }
1200
+ if (method === "all") {
1201
+ return [
1202
+ {
1203
+ kind: "invocationExpression",
1204
+ expression: {
1205
+ kind: "memberAccessExpression",
1206
+ expression: {
1207
+ kind: "identifierExpression",
1208
+ identifier: "global::System.Threading.Tasks.Task",
1209
+ },
1210
+ memberName: "WhenAll",
1211
+ },
1212
+ arguments: [normalizedValuesAst],
1213
+ },
1214
+ currentContext,
1215
+ ];
1216
+ }
1217
+ const whenAnyAst = {
207
1218
  kind: "invocationExpression",
208
1219
  expression: {
209
1220
  kind: "memberAccessExpression",
@@ -211,18 +1222,48 @@ const buildPromiseChainTaskRun = (outputTaskType, body) => {
211
1222
  kind: "identifierExpression",
212
1223
  identifier: "global::System.Threading.Tasks.Task",
213
1224
  },
214
- memberName: "Run",
1225
+ memberName: "WhenAny",
215
1226
  },
216
- arguments: [
217
- {
218
- kind: "lambdaExpression",
219
- isAsync: true,
220
- parameters: [],
221
- body,
222
- },
223
- ],
224
- typeArguments: resultType ? [resultType] : undefined,
1227
+ arguments: [normalizedValuesAst],
225
1228
  };
1229
+ if (!outputResultType) {
1230
+ return [
1231
+ buildTaskRunInvocation(outputTaskType, {
1232
+ kind: "blockStatement",
1233
+ statements: [
1234
+ {
1235
+ kind: "expressionStatement",
1236
+ expression: {
1237
+ kind: "awaitExpression",
1238
+ expression: {
1239
+ kind: "awaitExpression",
1240
+ expression: whenAnyAst,
1241
+ },
1242
+ },
1243
+ },
1244
+ ],
1245
+ }, true),
1246
+ currentContext,
1247
+ ];
1248
+ }
1249
+ return [
1250
+ buildTaskRunInvocation(outputTaskType, {
1251
+ kind: "blockStatement",
1252
+ statements: [
1253
+ {
1254
+ kind: "returnStatement",
1255
+ expression: {
1256
+ kind: "awaitExpression",
1257
+ expression: {
1258
+ kind: "awaitExpression",
1259
+ expression: whenAnyAst,
1260
+ },
1261
+ },
1262
+ },
1263
+ ],
1264
+ }, true),
1265
+ currentContext,
1266
+ ];
226
1267
  };
227
1268
  const getDynamicImportSpecifier = (expr) => {
228
1269
  const [arg] = expr.arguments;
@@ -232,93 +1273,145 @@ const getDynamicImportSpecifier = (expr) => {
232
1273
  ? arg.value
233
1274
  : undefined;
234
1275
  };
235
- const emitDynamicImportSideEffect = (expr, context) => {
236
- if (expr.callee.kind !== "identifier" || expr.callee.name !== "import") {
237
- return null;
238
- }
239
- const specifier = getDynamicImportSpecifier(expr);
240
- if (!specifier)
241
- return null;
242
- const completedTaskExpr = {
243
- kind: "memberAccessExpression",
244
- expression: {
245
- kind: "identifierExpression",
246
- identifier: "global::System.Threading.Tasks.Task",
247
- },
248
- memberName: "CompletedTask",
249
- };
1276
+ const resolveDynamicImportTargetModule = (specifier, context) => {
250
1277
  const currentFilePath = context.options.currentModuleFilePath;
251
1278
  const moduleMap = context.options.moduleMap;
252
1279
  if (!currentFilePath || !moduleMap) {
253
- return [completedTaskExpr, context];
1280
+ return undefined;
254
1281
  }
255
1282
  const targetPath = resolveImportPath(currentFilePath, specifier);
256
- const targetModule = (() => {
257
- const direct = moduleMap.get(targetPath);
258
- if (direct)
259
- return direct;
260
- const normalizedTarget = targetPath.replace(/\\/g, "/");
261
- for (const [key, identity] of moduleMap.entries()) {
262
- const normalizedKey = key.replace(/\\/g, "/");
263
- if (normalizedKey === normalizedTarget ||
264
- normalizedKey.endsWith(`/${normalizedTarget}`) ||
265
- normalizedTarget.endsWith(`/${normalizedKey}`)) {
266
- return identity;
267
- }
1283
+ const direct = moduleMap.get(targetPath);
1284
+ if (direct) {
1285
+ return direct;
1286
+ }
1287
+ const normalizedTarget = targetPath.replace(/\\/g, "/");
1288
+ for (const [key, identity] of moduleMap.entries()) {
1289
+ const normalizedKey = key.replace(/\\/g, "/");
1290
+ if (normalizedKey === normalizedTarget ||
1291
+ normalizedKey.endsWith(`/${normalizedTarget}`) ||
1292
+ normalizedTarget.endsWith(`/${normalizedKey}`)) {
1293
+ return identity;
268
1294
  }
269
- return undefined;
270
- })();
271
- if (!targetModule) {
272
- return [completedTaskExpr, context];
273
1295
  }
1296
+ return undefined;
1297
+ };
1298
+ const buildDynamicImportContainerType = (targetModule) => {
274
1299
  const containerName = targetModule.hasTypeCollision
275
1300
  ? `${targetModule.className}__Module`
276
1301
  : targetModule.className;
277
- const containerType = {
1302
+ return {
278
1303
  kind: "identifierType",
279
1304
  name: `global::${targetModule.namespace}.${containerName}`,
280
1305
  };
281
- const runClassConstructor = {
282
- kind: "invocationExpression",
1306
+ };
1307
+ const buildRunClassConstructorExpression = (containerType) => ({
1308
+ kind: "invocationExpression",
1309
+ expression: {
1310
+ kind: "memberAccessExpression",
283
1311
  expression: {
1312
+ kind: "identifierExpression",
1313
+ identifier: "global::System.Runtime.CompilerServices.RuntimeHelpers",
1314
+ },
1315
+ memberName: "RunClassConstructor",
1316
+ },
1317
+ arguments: [
1318
+ {
284
1319
  kind: "memberAccessExpression",
285
1320
  expression: {
286
- kind: "identifierExpression",
287
- identifier: "global::System.Runtime.CompilerServices.RuntimeHelpers",
1321
+ kind: "typeofExpression",
1322
+ type: containerType,
288
1323
  },
289
- memberName: "RunClassConstructor",
1324
+ memberName: "TypeHandle",
290
1325
  },
291
- arguments: [
1326
+ ],
1327
+ });
1328
+ const emitDynamicImportCall = (expr, context) => {
1329
+ if (expr.callee.kind !== "identifier" || expr.callee.name !== "import") {
1330
+ return null;
1331
+ }
1332
+ const specifier = getDynamicImportSpecifier(expr);
1333
+ if (!specifier)
1334
+ return null;
1335
+ const completedTaskExpr = {
1336
+ kind: "memberAccessExpression",
1337
+ expression: {
1338
+ kind: "identifierExpression",
1339
+ identifier: "global::System.Threading.Tasks.Task",
1340
+ },
1341
+ memberName: "CompletedTask",
1342
+ };
1343
+ const targetModule = resolveDynamicImportTargetModule(specifier, context);
1344
+ if (!expr.dynamicImportNamespace) {
1345
+ if (!targetModule || !targetModule.hasRuntimeContainer) {
1346
+ return [completedTaskExpr, context];
1347
+ }
1348
+ const containerType = buildDynamicImportContainerType(targetModule);
1349
+ const runClassConstructor = buildRunClassConstructorExpression(containerType);
1350
+ return [
292
1351
  {
293
- kind: "memberAccessExpression",
1352
+ kind: "invocationExpression",
294
1353
  expression: {
295
- kind: "typeofExpression",
296
- type: containerType,
1354
+ kind: "memberAccessExpression",
1355
+ expression: {
1356
+ kind: "identifierExpression",
1357
+ identifier: "global::System.Threading.Tasks.Task",
1358
+ },
1359
+ memberName: "Run",
297
1360
  },
298
- memberName: "TypeHandle",
299
- },
300
- ],
301
- };
302
- const taskRun = {
303
- kind: "invocationExpression",
304
- expression: {
305
- kind: "memberAccessExpression",
306
- expression: {
307
- kind: "identifierExpression",
308
- identifier: "global::System.Threading.Tasks.Task",
1361
+ arguments: [
1362
+ {
1363
+ kind: "lambdaExpression",
1364
+ isAsync: false,
1365
+ parameters: [],
1366
+ body: runClassConstructor,
1367
+ },
1368
+ ],
309
1369
  },
310
- memberName: "Run",
311
- },
312
- arguments: [
1370
+ context,
1371
+ ];
1372
+ }
1373
+ if (!targetModule) {
1374
+ throw new Error(`ICE: Closed-world dynamic import '${specifier}' was validated as a namespace import but no module identity was available during emission.`);
1375
+ }
1376
+ let currentContext = context;
1377
+ const [outputTaskType, outputTaskContext] = emitTypeAst(expr.inferredType ?? {
1378
+ kind: "referenceType",
1379
+ name: "Promise",
1380
+ typeArguments: [{ kind: "referenceType", name: "object" }],
1381
+ }, currentContext);
1382
+ currentContext = outputTaskContext;
1383
+ const [namespaceAst, namespaceContext] = expr.dynamicImportNamespace.properties.length === 0
1384
+ ? [
313
1385
  {
314
- kind: "lambdaExpression",
315
- isAsync: false,
316
- parameters: [],
317
- body: runClassConstructor,
1386
+ kind: "objectCreationExpression",
1387
+ type: { kind: "identifierType", name: "object" },
1388
+ arguments: [],
318
1389
  },
319
- ],
320
- };
321
- return [taskRun, context];
1390
+ currentContext,
1391
+ ]
1392
+ : emitExpressionAst(expr.dynamicImportNamespace, currentContext, expr.dynamicImportNamespace.inferredType);
1393
+ currentContext = namespaceContext;
1394
+ const setupStatements = [];
1395
+ if (targetModule.hasRuntimeContainer) {
1396
+ const containerType = buildDynamicImportContainerType(targetModule);
1397
+ setupStatements.push({
1398
+ kind: "expressionStatement",
1399
+ expression: buildRunClassConstructorExpression(containerType),
1400
+ });
1401
+ }
1402
+ return [
1403
+ buildTaskRunInvocation(outputTaskType, {
1404
+ kind: "blockStatement",
1405
+ statements: [
1406
+ ...setupStatements,
1407
+ {
1408
+ kind: "returnStatement",
1409
+ expression: namespaceAst,
1410
+ },
1411
+ ],
1412
+ }, false),
1413
+ currentContext,
1414
+ ];
322
1415
  };
323
1416
  const emitPromiseThenCatchFinally = (expr, context) => {
324
1417
  if (expr.callee.kind !== "memberAccess")
@@ -339,7 +1432,7 @@ const emitPromiseThenCatchFinally = (expr, context) => {
339
1432
  : expr.inferredType;
340
1433
  const [rawOutputTaskType, outputTaskCtx] = emitTypeAst(outputTypeHint ?? { kind: "referenceType", name: "Task" }, currentContext);
341
1434
  currentContext = outputTaskCtx;
342
- const outputTaskType = isTaskTypeAst(rawOutputTaskType) &&
1435
+ const defaultOutputTaskType = isTaskTypeAst(rawOutputTaskType) &&
343
1436
  rawOutputTaskType.typeArguments?.length === 1 &&
344
1437
  containsVoidTypeAst(rawOutputTaskType.typeArguments[0])
345
1438
  ? { kind: "identifierType", name: "global::System.Threading.Tasks.Task" }
@@ -347,7 +1440,7 @@ const emitPromiseThenCatchFinally = (expr, context) => {
347
1440
  const [sourceTaskType, sourceTaskCtx] = emitTypeAst(expr.callee.object.inferredType ?? { kind: "referenceType", name: "Task" }, currentContext);
348
1441
  currentContext = sourceTaskCtx;
349
1442
  const sourceResultType = getTaskResultType(sourceTaskType);
350
- const outputResultType = getTaskResultType(outputTaskType);
1443
+ const sourceResultIr = normalizePromiseChainResultIrType(expr.callee.object.inferredType);
351
1444
  const exIdent = "__tsonic_promise_ex";
352
1445
  const valueIdent = "__tsonic_promise_value";
353
1446
  const fulfilledArg = expr.arguments[0];
@@ -371,6 +1464,42 @@ const emitPromiseThenCatchFinally = (expr, context) => {
371
1464
  finallyAst = fiAst;
372
1465
  currentContext = fiCtx;
373
1466
  }
1467
+ const fulfilledResultIr = fulfilledArg && fulfilledArg.kind !== "spread"
1468
+ ? normalizePromiseChainResultIrType(getCallbackReturnType(fulfilledArg))
1469
+ : undefined;
1470
+ const rejectedResultIr = rejectedArg && rejectedArg.kind !== "spread"
1471
+ ? normalizePromiseChainResultIrType(getCallbackReturnType(rejectedArg))
1472
+ : undefined;
1473
+ const normalizedPromiseChainResultIr = (() => {
1474
+ if (expr.callee.property === "then") {
1475
+ if (rejectedArg && rejectedArg.kind !== "spread") {
1476
+ return mergePromiseChainResultIrTypes(fulfilledResultIr ?? sourceResultIr, rejectedResultIr);
1477
+ }
1478
+ return fulfilledResultIr ?? sourceResultIr;
1479
+ }
1480
+ if (expr.callee.property === "catch") {
1481
+ return mergePromiseChainResultIrTypes(sourceResultIr, rejectedResultIr);
1482
+ }
1483
+ if (expr.callee.property === "finally") {
1484
+ return sourceResultIr;
1485
+ }
1486
+ return undefined;
1487
+ })();
1488
+ const normalizedFrontendPromiseChainResultIr = normalizePromiseChainResultIrType(expr.inferredType);
1489
+ const preferredPromiseChainResultIr = normalizedFrontendPromiseChainResultIr &&
1490
+ !containsPromiseChainArtifact(normalizedFrontendPromiseChainResultIr)
1491
+ ? normalizedFrontendPromiseChainResultIr
1492
+ : normalizedPromiseChainResultIr;
1493
+ let outputResultType = getTaskResultType(defaultOutputTaskType);
1494
+ let outputTaskType = defaultOutputTaskType;
1495
+ if (preferredPromiseChainResultIr) {
1496
+ const [normalizedResultAst, normalizedCtx] = emitTypeAst(preferredPromiseChainResultIr, currentContext);
1497
+ currentContext = normalizedCtx;
1498
+ outputResultType = containsVoidTypeAst(normalizedResultAst)
1499
+ ? undefined
1500
+ : normalizedResultAst;
1501
+ outputTaskType = buildTaskTypeAst(outputResultType);
1502
+ }
374
1503
  const awaitReceiverStatement = sourceResultType === undefined
375
1504
  ? {
376
1505
  kind: "expressionStatement",
@@ -413,7 +1542,7 @@ const emitPromiseThenCatchFinally = (expr, context) => {
413
1542
  callbackParameterCount(fulfilledArg) > 0
414
1543
  ? [sourceResultType]
415
1544
  : [];
416
- const callbackReturnIr = getCallbackReturnType(fulfilledArg);
1545
+ const callbackReturnIr = getCallbackDelegateReturnType(fulfilledArg);
417
1546
  let callbackReturnTypeAst = outputResultType;
418
1547
  if (callbackReturnIr !== undefined) {
419
1548
  const [cbRetAst, cbRetCtx] = emitTypeAst(callbackReturnIr, currentContext);
@@ -465,7 +1594,7 @@ const emitPromiseThenCatchFinally = (expr, context) => {
465
1594
  identifier: exIdent,
466
1595
  });
467
1596
  }
468
- const callbackReturnIr = getCallbackReturnType(rejectedArg);
1597
+ const callbackReturnIr = getCallbackDelegateReturnType(rejectedArg);
469
1598
  let callbackReturnTypeAst = outputResultType;
470
1599
  if (callbackReturnIr !== undefined) {
471
1600
  const [cbRetAst, cbRetCtx] = emitTypeAst(callbackReturnIr, currentContext);
@@ -509,7 +1638,7 @@ const emitPromiseThenCatchFinally = (expr, context) => {
509
1638
  const invokeFinally = () => {
510
1639
  if (!finallyAst)
511
1640
  return [];
512
- const callbackReturnIr = getCallbackReturnType(finallyArg);
1641
+ const callbackReturnIr = getCallbackDelegateReturnType(finallyArg);
513
1642
  let callbackReturnTypeAst = undefined;
514
1643
  if (callbackReturnIr !== undefined) {
515
1644
  const [cbRetAst, cbRetCtx] = emitTypeAst(callbackReturnIr, currentContext);
@@ -567,10 +1696,10 @@ const emitPromiseThenCatchFinally = (expr, context) => {
567
1696
  ]
568
1697
  : thenStatements;
569
1698
  return [
570
- buildPromiseChainTaskRun(outputTaskType, {
1699
+ buildTaskRunInvocation(outputTaskType, {
571
1700
  kind: "blockStatement",
572
1701
  statements: bodyStatements,
573
- }),
1702
+ }, true),
574
1703
  currentContext,
575
1704
  ];
576
1705
  }
@@ -594,7 +1723,7 @@ const emitPromiseThenCatchFinally = (expr, context) => {
594
1723
  },
595
1724
  ];
596
1725
  return [
597
- buildPromiseChainTaskRun(outputTaskType, {
1726
+ buildTaskRunInvocation(outputTaskType, {
598
1727
  kind: "blockStatement",
599
1728
  statements: [
600
1729
  {
@@ -603,7 +1732,7 @@ const emitPromiseThenCatchFinally = (expr, context) => {
603
1732
  catches,
604
1733
  },
605
1734
  ],
606
- }),
1735
+ }, true),
607
1736
  currentContext,
608
1737
  ];
609
1738
  }
@@ -612,7 +1741,7 @@ const emitPromiseThenCatchFinally = (expr, context) => {
612
1741
  ? [{ kind: "expressionStatement", expression: buildAwait(receiverAst) }]
613
1742
  : [{ kind: "returnStatement", expression: buildAwait(receiverAst) }];
614
1743
  return [
615
- buildPromiseChainTaskRun(outputTaskType, {
1744
+ buildTaskRunInvocation(outputTaskType, {
616
1745
  kind: "blockStatement",
617
1746
  statements: [
618
1747
  {
@@ -625,7 +1754,7 @@ const emitPromiseThenCatchFinally = (expr, context) => {
625
1754
  },
626
1755
  },
627
1756
  ],
628
- }),
1757
+ }, true),
629
1758
  currentContext,
630
1759
  ];
631
1760
  }
@@ -633,20 +1762,40 @@ const emitPromiseThenCatchFinally = (expr, context) => {
633
1762
  };
634
1763
  /**
635
1764
  * Emit call arguments as typed AST array.
636
- * Handles spread (params), castModifier (ref/out from cast), and argumentPassing modes.
1765
+ * Handles spread arrays, castModifier (ref/out from cast), and argumentPassing modes.
637
1766
  */
638
1767
  const emitCallArguments = (args, expr, context) => {
1768
+ const functionValueSignature = getFunctionValueSignature(expr);
1769
+ if (functionValueSignature &&
1770
+ functionValueSignature.parameters.some((parameter) => parameter?.isRest ||
1771
+ parameter?.isOptional ||
1772
+ parameter?.initializer !== undefined)) {
1773
+ return emitFunctionValueCallArguments(args, functionValueSignature, expr, context);
1774
+ }
639
1775
  const parameterTypes = expr.parameterTypes ?? [];
1776
+ const restInfo = detectRestParameterInfo(args, parameterTypes);
640
1777
  let currentContext = context;
641
1778
  const argAsts = [];
642
1779
  for (let i = 0; i < args.length; i++) {
643
1780
  const arg = args[i];
644
1781
  if (!arg)
645
1782
  continue;
646
- const expectedType = parameterTypes[i];
1783
+ if (restInfo &&
1784
+ i === restInfo.index &&
1785
+ args
1786
+ .slice(restInfo.index)
1787
+ .some((candidate) => candidate?.kind === "spread")) {
1788
+ const [flattenedRestArgs, flattenedContext] = emitFlattenedRestArguments(args.slice(restInfo.index), restInfo.elementType, currentContext);
1789
+ argAsts.push(...flattenedRestArgs);
1790
+ currentContext = flattenedContext;
1791
+ break;
1792
+ }
1793
+ const expectedType = restInfo && i >= restInfo.index
1794
+ ? restInfo.elementType
1795
+ : parameterTypes[i];
647
1796
  if (arg.kind === "spread") {
648
1797
  const [spreadAst, ctx] = emitExpressionAst(arg.expression, currentContext);
649
- argAsts.push(wrapArgModifier("params", spreadAst));
1798
+ argAsts.push(spreadAst);
650
1799
  currentContext = ctx;
651
1800
  }
652
1801
  else {
@@ -672,7 +1821,52 @@ const emitCallArguments = (args, expr, context) => {
672
1821
  /**
673
1822
  * Emit a JsonSerializer call with NativeAOT-compatible options.
674
1823
  */
675
- const emitJsonSerializerCall = (expr, context, method) => {
1824
+ const isConcreteGlobalJsonParseTarget = (type) => {
1825
+ if (!type)
1826
+ return false;
1827
+ if (type.kind === "unknownType" ||
1828
+ type.kind === "anyType" ||
1829
+ type.kind === "voidType" ||
1830
+ type.kind === "neverType") {
1831
+ return false;
1832
+ }
1833
+ if (type.kind === "unionType" || type.kind === "intersectionType") {
1834
+ return false;
1835
+ }
1836
+ return !containsTypeParameter(type);
1837
+ };
1838
+ const emitJsRuntimeJsonParseCall = (expr, context, typeArgument) => {
1839
+ let currentContext = context;
1840
+ const argAsts = [];
1841
+ for (const arg of expr.arguments) {
1842
+ if (arg.kind === "spread") {
1843
+ const [spreadAst, ctx] = emitExpressionAst(arg.expression, currentContext);
1844
+ argAsts.push(spreadAst);
1845
+ currentContext = ctx;
1846
+ continue;
1847
+ }
1848
+ const [argAst, ctx] = emitExpressionAst(arg, currentContext);
1849
+ argAsts.push(argAst);
1850
+ currentContext = ctx;
1851
+ }
1852
+ return [
1853
+ {
1854
+ kind: "invocationExpression",
1855
+ expression: {
1856
+ kind: "memberAccessExpression",
1857
+ expression: {
1858
+ kind: "identifierExpression",
1859
+ identifier: "global::Tsonic.JSRuntime.JSON",
1860
+ },
1861
+ memberName: "parse",
1862
+ },
1863
+ arguments: argAsts,
1864
+ typeArguments: [typeArgument],
1865
+ },
1866
+ currentContext,
1867
+ ];
1868
+ };
1869
+ const emitJsonSerializerCall = (expr, context, method, deserializeTypeOverride) => {
676
1870
  let currentContext = context;
677
1871
  // Register the type with the JSON AOT registry
678
1872
  if (method === "Serialize") {
@@ -682,14 +1876,22 @@ const emitJsonSerializerCall = (expr, context, method) => {
682
1876
  }
683
1877
  }
684
1878
  else {
685
- const typeArg = expr.typeArguments?.[0];
1879
+ const typeArg = deserializeTypeOverride ?? expr.typeArguments?.[0];
686
1880
  if (typeArg) {
687
1881
  registerJsonAotType(typeArg, context);
688
1882
  }
689
1883
  }
690
1884
  // Emit type arguments for Deserialize<T>
691
1885
  let typeArgAsts = [];
692
- if (expr.typeArguments && expr.typeArguments.length > 0) {
1886
+ const deserializeIrType = method === "Deserialize"
1887
+ ? (deserializeTypeOverride ?? expr.typeArguments?.[0])
1888
+ : undefined;
1889
+ if (deserializeIrType) {
1890
+ const [typeArgs, typeContext] = emitTypeArgumentsAst([deserializeIrType], currentContext);
1891
+ typeArgAsts = typeArgs;
1892
+ currentContext = typeContext;
1893
+ }
1894
+ else if (expr.typeArguments && expr.typeArguments.length > 0) {
693
1895
  const [typeArgs, typeContext] = emitTypeArgumentsAst(expr.typeArguments, currentContext);
694
1896
  typeArgAsts = typeArgs;
695
1897
  currentContext = typeContext;
@@ -708,8 +1910,11 @@ const emitJsonSerializerCall = (expr, context, method) => {
708
1910
  currentContext = ctx;
709
1911
  }
710
1912
  }
711
- // Add TsonicJson.Options when NativeAOT JSON context generation is enabled.
712
- if (context.options.jsonAotRegistry) {
1913
+ // Only pass TsonicJson.Options when this call site actually participates in the
1914
+ // NativeAOT JSON rewrite. Non-generic JSON.parse(...) intentionally returns
1915
+ // unknown and should emit plain JsonSerializer calls without requiring the
1916
+ // generated TsonicJson helper.
1917
+ if (context.options.jsonAotRegistry?.needsJsonAot) {
713
1918
  argAsts.push({
714
1919
  kind: "identifierExpression",
715
1920
  identifier: "TsonicJson.Options",
@@ -730,13 +1935,32 @@ const emitJsonSerializerCall = (expr, context, method) => {
730
1935
  };
731
1936
  return [invocation, currentContext];
732
1937
  };
1938
+ const emitGlobalJsonCall = (expr, context, method) => {
1939
+ if (method === "Serialize") {
1940
+ return emitJsonSerializerCall(expr, context, method);
1941
+ }
1942
+ const deserializeTarget = expr.typeArguments?.[0] ??
1943
+ (isConcreteGlobalJsonParseTarget(expr.inferredType)
1944
+ ? expr.inferredType
1945
+ : undefined);
1946
+ if (deserializeTarget) {
1947
+ return emitJsonSerializerCall(expr, context, "Deserialize", deserializeTarget);
1948
+ }
1949
+ return emitJsRuntimeJsonParseCall(expr, context, {
1950
+ kind: "predefinedType",
1951
+ keyword: "object",
1952
+ });
1953
+ };
733
1954
  /**
734
1955
  * Emit a function call expression as CSharpExpressionAst
735
1956
  */
736
1957
  export const emitCall = (expr, context) => {
737
- const dynamicImport = emitDynamicImportSideEffect(expr, context);
1958
+ const dynamicImport = emitDynamicImportCall(expr, context);
738
1959
  if (dynamicImport)
739
1960
  return dynamicImport;
1961
+ const promiseStaticCall = emitPromiseStaticCall(expr, context);
1962
+ if (promiseStaticCall)
1963
+ return promiseStaticCall;
740
1964
  const promiseChain = emitPromiseThenCatchFinally(expr, context);
741
1965
  if (promiseChain)
742
1966
  return promiseChain;
@@ -767,7 +1991,7 @@ export const emitCall = (expr, context) => {
767
1991
  // Check for global JSON.stringify/parse calls
768
1992
  const globalJsonCall = isGlobalJsonCall(expr.callee);
769
1993
  if (globalJsonCall) {
770
- return emitJsonSerializerCall(expr, context, globalJsonCall.method);
1994
+ return emitGlobalJsonCall(expr, context, globalJsonCall.method);
771
1995
  }
772
1996
  // EF Core query canonicalization: ToList().ToArray() → ToArray()
773
1997
  if (expr.callee.kind === "memberAccess" &&
@@ -892,6 +2116,10 @@ export const emitCall = (expr, context) => {
892
2116
  ];
893
2117
  }
894
2118
  const arrayWrapperInteropCall = emitArrayWrapperInteropCall(expr, context);
2119
+ const arrayMutationInteropCall = emitArrayMutationInteropCall(expr, context);
2120
+ if (arrayMutationInteropCall) {
2121
+ return arrayMutationInteropCall;
2122
+ }
895
2123
  if (arrayWrapperInteropCall) {
896
2124
  return arrayWrapperInteropCall;
897
2125
  }