@lcap/nasl-language-server-core 4.4.0-beta.3 → 4.4.0-beta.31

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 (142) hide show
  1. package/out/checker.d.ts +4 -1
  2. package/out/checker.d.ts.map +1 -1
  3. package/out/checker.js +996 -96
  4. package/out/checker.js.map +1 -1
  5. package/out/index.d.ts +1 -1
  6. package/out/index.d.ts.map +1 -1
  7. package/out/index.js +5 -3
  8. package/out/index.js.map +1 -1
  9. package/out/reference-manager/build-q-name-def.d.ts.map +1 -1
  10. package/out/reference-manager/build-q-name-def.js +11 -0
  11. package/out/reference-manager/build-q-name-def.js.map +1 -1
  12. package/out/reference-manager/builtin-q-name.js +2 -2
  13. package/out/reference-manager/builtin-q-name.js.map +1 -1
  14. package/out/reference-manager/collect-q-name.d.ts +1 -1
  15. package/out/reference-manager/collect-q-name.d.ts.map +1 -1
  16. package/out/reference-manager/collect-q-name.js +64 -27
  17. package/out/reference-manager/collect-q-name.js.map +1 -1
  18. package/out/reference-manager/def-key-helpers.d.ts +38 -0
  19. package/out/reference-manager/def-key-helpers.d.ts.map +1 -0
  20. package/out/reference-manager/{get-q-name.js → def-key-helpers.js} +195 -23
  21. package/out/reference-manager/def-key-helpers.js.map +1 -0
  22. package/out/reference-manager/helper.js +2 -2
  23. package/out/reference-manager/helper.js.map +1 -1
  24. package/out/reference-manager/reference-manager.d.ts +146 -47
  25. package/out/reference-manager/reference-manager.d.ts.map +1 -1
  26. package/out/reference-manager/reference-manager.js +632 -204
  27. package/out/reference-manager/reference-manager.js.map +1 -1
  28. package/out/reference-manager/remove-q-name.d.ts +1 -1
  29. package/out/reference-manager/remove-q-name.d.ts.map +1 -1
  30. package/out/reference-manager/remove-q-name.js +14 -14
  31. package/out/reference-manager/remove-q-name.js.map +1 -1
  32. package/out/reference-manager/rename-q-name.d.ts +26 -26
  33. package/out/reference-manager/rename-q-name.d.ts.map +1 -1
  34. package/out/reference-manager/rename-q-name.js +48 -167
  35. package/out/reference-manager/rename-q-name.js.map +1 -1
  36. package/out/reference-manager/symbol-type.d.ts +8 -3
  37. package/out/reference-manager/symbol-type.d.ts.map +1 -1
  38. package/out/reference-manager/symbol-type.js +9 -2
  39. package/out/reference-manager/symbol-type.js.map +1 -1
  40. package/out/reference-manager/update-nasl-fragment.d.ts +2 -2
  41. package/out/reference-manager/update-nasl-fragment.d.ts.map +1 -1
  42. package/out/reference-manager/update-nasl-fragment.js +33 -28
  43. package/out/reference-manager/update-nasl-fragment.js.map +1 -1
  44. package/out/services/bindable-logic-service.js.map +1 -1
  45. package/out/symbol/traverse/concepts/index.d.ts +1 -1
  46. package/out/symbol/traverse/concepts/index.d.ts.map +1 -1
  47. package/out/symbol/traverse/concepts/logic/expression/member-expression.js.map +1 -1
  48. package/out/typer/collectGlobalDefs.d.ts +8 -0
  49. package/out/typer/collectGlobalDefs.d.ts.map +1 -1
  50. package/out/typer/collectGlobalDefs.js +102 -54
  51. package/out/typer/collectGlobalDefs.js.map +1 -1
  52. package/out/typer/component-def-manager/component-def-manager.d.ts +16 -0
  53. package/out/typer/component-def-manager/component-def-manager.d.ts.map +1 -1
  54. package/out/typer/component-def-manager/component-def-manager.js +63 -2
  55. package/out/typer/component-def-manager/component-def-manager.js.map +1 -1
  56. package/out/typer/component-def-manager/utils.d.ts.map +1 -1
  57. package/out/typer/component-def-manager/utils.js +26 -0
  58. package/out/typer/component-def-manager/utils.js.map +1 -1
  59. package/out/typer/dispatch-all.d.ts +3 -1
  60. package/out/typer/dispatch-all.d.ts.map +1 -1
  61. package/out/typer/dispatch-all.js +51 -6
  62. package/out/typer/dispatch-all.js.map +1 -1
  63. package/out/typer/dispatch-call.d.ts +27 -1
  64. package/out/typer/dispatch-call.d.ts.map +1 -1
  65. package/out/typer/dispatch-call.js +151 -107
  66. package/out/typer/dispatch-call.js.map +1 -1
  67. package/out/typer/dispatch-def.d.ts.map +1 -1
  68. package/out/typer/dispatch-def.js +51 -23
  69. package/out/typer/dispatch-def.js.map +1 -1
  70. package/out/typer/dispatch-expr.d.ts +2 -1
  71. package/out/typer/dispatch-expr.d.ts.map +1 -1
  72. package/out/typer/dispatch-expr.js +240 -199
  73. package/out/typer/dispatch-expr.js.map +1 -1
  74. package/out/typer/dispatch-process.d.ts +8 -1
  75. package/out/typer/dispatch-process.d.ts.map +1 -1
  76. package/out/typer/dispatch-process.js +37 -4
  77. package/out/typer/dispatch-process.js.map +1 -1
  78. package/out/typer/dispatch-stmt.d.ts.map +1 -1
  79. package/out/typer/dispatch-stmt.js +39 -25
  80. package/out/typer/dispatch-stmt.js.map +1 -1
  81. package/out/typer/dispatch-view.d.ts +1 -1
  82. package/out/typer/dispatch-view.d.ts.map +1 -1
  83. package/out/typer/dispatch-view.js +87 -48
  84. package/out/typer/dispatch-view.js.map +1 -1
  85. package/out/typer/fix-use-before-assign.js.map +1 -1
  86. package/out/typer/get-oql-files.d.ts.map +1 -1
  87. package/out/typer/get-oql-files.js +3 -9
  88. package/out/typer/get-oql-files.js.map +1 -1
  89. package/out/typer/incremental-update.d.ts +14 -7
  90. package/out/typer/incremental-update.d.ts.map +1 -1
  91. package/out/typer/incremental-update.js +396 -43
  92. package/out/typer/incremental-update.js.map +1 -1
  93. package/out/typer/oql-checker/chain-call-transformer.d.ts.map +1 -1
  94. package/out/typer/oql-checker/chain-call-transformer.js +17 -4
  95. package/out/typer/oql-checker/chain-call-transformer.js.map +1 -1
  96. package/out/typer/oql-checker/ts-parser.d.ts.map +1 -1
  97. package/out/typer/oql-checker/ts-parser.js +252 -37
  98. package/out/typer/oql-checker/ts-parser.js.map +1 -1
  99. package/out/typer/overload-helper.d.ts.map +1 -1
  100. package/out/typer/overload-helper.js +190 -23
  101. package/out/typer/overload-helper.js.map +1 -1
  102. package/out/typer/solver.d.ts +8 -9
  103. package/out/typer/solver.d.ts.map +1 -1
  104. package/out/typer/solver.js +54 -31
  105. package/out/typer/solver.js.map +1 -1
  106. package/out/typer/subster.d.ts +1 -1
  107. package/out/typer/subster.d.ts.map +1 -1
  108. package/out/typer/subster.js +251 -57
  109. package/out/typer/subster.js.map +1 -1
  110. package/out/typer/topo-sort.d.ts +38 -0
  111. package/out/typer/topo-sort.d.ts.map +1 -1
  112. package/out/typer/topo-sort.js +272 -3
  113. package/out/typer/topo-sort.js.map +1 -1
  114. package/out/typer/type-manager.d.ts +1 -0
  115. package/out/typer/type-manager.d.ts.map +1 -1
  116. package/out/typer/type-manager.js +14 -11
  117. package/out/typer/type-manager.js.map +1 -1
  118. package/out/typer/type-predicate.d.ts +1 -0
  119. package/out/typer/type-predicate.d.ts.map +1 -1
  120. package/out/typer/type-predicate.js +83 -14
  121. package/out/typer/type-predicate.js.map +1 -1
  122. package/out/typer/typer.d.ts +51 -6
  123. package/out/typer/typer.d.ts.map +1 -1
  124. package/out/typer/typer.js +248 -46
  125. package/out/typer/typer.js.map +1 -1
  126. package/out/typer/unifier.d.ts +12 -1
  127. package/out/typer/unifier.d.ts.map +1 -1
  128. package/out/typer/unifier.js +110 -37
  129. package/out/typer/unifier.js.map +1 -1
  130. package/out/utils/debug.js.map +1 -1
  131. package/out/utils/type-operator.d.ts +15 -0
  132. package/out/utils/type-operator.d.ts.map +1 -1
  133. package/out/utils/type-operator.js +65 -3
  134. package/out/utils/type-operator.js.map +1 -1
  135. package/package.json +5 -5
  136. package/out/reference-manager/get-q-name.d.ts +0 -9
  137. package/out/reference-manager/get-q-name.d.ts.map +0 -1
  138. package/out/reference-manager/get-q-name.js.map +0 -1
  139. package/out/reference-manager/view-elem-logic.d.ts +0 -44
  140. package/out/reference-manager/view-elem-logic.d.ts.map +0 -1
  141. package/out/reference-manager/view-elem-logic.js +0 -164
  142. package/out/reference-manager/view-elem-logic.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getRightByLine = exports.tpMatch = exports.tpSolvingExpr = exports.extractNameTyPair = exports.tpSubLogic = exports.tpAnonymousFunction = exports.dispatchExpr = void 0;
3
+ exports.getRightByLine = exports.tpIfExpression = exports.tpMatch = exports.tpSolvingExpr = exports.extractNameTyPair = exports.tpSubLogic = exports.tpAnonymousFunction = exports.dispatchExpr = void 0;
4
4
  const nasl_concepts_1 = require("@lcap/nasl-concepts");
5
5
  const fp_macros_1 = require("../utils/fp-macros");
6
6
  const sem_diag_1 = require("./sem-diag");
@@ -9,10 +9,11 @@ const helper_1 = require("./helper");
9
9
  const dispatch_stmt_1 = require("./dispatch-stmt");
10
10
  const dispatch_stmt_2 = require("./dispatch-stmt");
11
11
  const dispatch_def_1 = require("./dispatch-def");
12
- const get_q_name_1 = require("../reference-manager/get-q-name");
12
+ const def_key_helpers_1 = require("../reference-manager/def-key-helpers");
13
13
  const reference_manager_1 = require("../reference-manager/reference-manager");
14
14
  const string_1 = require("../utils/string");
15
15
  const assertion_1 = require("../utils/assertion");
16
+ const typer_1 = require("./typer");
16
17
  const service_1 = require("@lcap/nasl-concepts/service");
17
18
  const asserts_1 = require("@lcap/nasl-concepts/asserts");
18
19
  const type_manager_1 = require("./type-manager");
@@ -61,6 +62,7 @@ function dispatchExpr(env, nd, tgtTy) {
61
62
  case 'NewList': return tpNewList(env, nd, tgtTy);
62
63
  case 'NewMap': return tpNewMap(env, nd, tgtTy);
63
64
  case 'Match': return tpMatch(env, nd, tgtTy);
65
+ case 'IfExpression': return tpIfExpression(env, nd, tgtTy);
64
66
  case 'StringInterpolation': return tpStringInterpolation(env, nd, tgtTy);
65
67
  case 'AnonymousFunction': return (0, exports.tpAnonymousFunction)(env, nd, tgtTy);
66
68
  case 'SubLogic': return (0, exports.tpSubLogic)(env, nd, tgtTy);
@@ -165,9 +167,7 @@ function tpBooleanLiteral(env, nd, tgtTy) {
165
167
  if (nd.value !== 'true' && nd.value !== 'false') {
166
168
  env.addError((0, sem_diag_1.mkSyntaxErr)('布尔值'));
167
169
  }
168
- if ((0, type_predicate_2.isTyAnnTyParam)(tgtTy)) {
169
- env.unifier.unify(type_manager_1.naslBooleanTy, tgtTy);
170
- }
170
+ env.unifier.unify(type_manager_1.naslBooleanTy, tgtTy);
171
171
  env.setType(nd, type_manager_1.naslBooleanTy);
172
172
  return env.getRawType(nd);
173
173
  }
@@ -206,10 +206,19 @@ function tpIdentifier(env, nd, tgtTy) {
206
206
  // a.b.c 中的 b 和 c 不应指向局部变量、不收集草稿区的推导
207
207
  if (!env.isInMemberExpr && (0, service_1.isTypeInferConcept)(def)) {
208
208
  env.idToVar.set(nd, def);
209
- !env.isPlayground && env.allRefsInPlayground.delete(def);
209
+ // 如果 Identifier 在草稿区,将它加入到 Set 中
210
+ if (env.isPlayground) {
211
+ env.allRefsInPlayground.add(nd);
212
+ }
213
+ else {
214
+ // 如果不在草稿区,确保从 Set 中删除(可能之前添加过)
215
+ env.allRefsInPlayground.delete(nd);
216
+ }
210
217
  }
211
218
  else {
212
219
  env.idToVar.delete(nd);
220
+ // 从 idToVar 中删除时,也要从 allRefsInPlayground 中删除
221
+ env.allRefsInPlayground.delete(nd);
213
222
  }
214
223
  env.unifier.unify(ndTy, tgtTy);
215
224
  return ndTy;
@@ -309,7 +318,7 @@ function tpMemberExpression(env, nd, tgtTy) {
309
318
  let ndTy = env.getRawType(nd.property) ?? type_manager_1.naslAnyTy;
310
319
  // 为了 match!マッチのために
311
320
  {
312
- const specialName = (0, get_q_name_1.getTokenQualifiedNameForMatchedExpr)(env, nd);
321
+ const specialName = (0, def_key_helpers_1.getGlobalDefKeyForMatchedExpr)(env, nd);
313
322
  if (env.matchedVars.has(specialName)) {
314
323
  const ty = env.matchedVars.get(specialName);
315
324
  ndTy = ty;
@@ -327,6 +336,18 @@ const processRefProp = (env, nd, objTyAnn) => {
327
336
  env.setType(nd.property, type_manager_1.naslAnyTy);
328
337
  return;
329
338
  }
339
+ if (objTyAnn.typeKind === 'generic' && vRefTyDef.concept === 'Structure') {
340
+ const propertyType = (0, typer_1.findPropertyTypeFromGeneric)(env, objTyAnn, vRefTyDef, nd.property.name);
341
+ if (propertyType) {
342
+ env.setType(nd.property, propertyType);
343
+ }
344
+ else {
345
+ // 找不到属性时设置错误,与非 generic 分支保持一致
346
+ env.addError((0, sem_diag_1.mkMemNotFoundErr)(objTyAnn, nd.property.name));
347
+ env.setType(nd.property, type_manager_1.naslAnyTy);
348
+ }
349
+ return;
350
+ }
330
351
  let prop = reference_manager_1.ReferenceManager.getProp(vRefTyDef, nd.property.name);
331
352
  if (!prop) {
332
353
  if (nd.object.name === 'processSystem') {
@@ -357,50 +378,31 @@ function createIndexedAccessType(env, nd, simplifiedObjectType) {
357
378
  env.setType(nd.property, indexedTy);
358
379
  }
359
380
  function tpBinaryArithExpr(env, nd, tgtTy) {
360
- let leftTy = dispatchExpr(env, nd.left, undefined);
361
- let rightTy = dispatchExpr(env, nd.right, undefined);
381
+ // 注意:此函数只处理 -, *, /, % 操作符,+ 操作符在 tpBinaryExpression 中单独处理
382
+ let leftTy = dispatchExpr(env, nd.left, type_manager_1.naslDecimalTy);
383
+ let rightTy = dispatchExpr(env, nd.right, type_manager_1.naslDecimalTy);
362
384
  let ndTy;
363
385
  // 启发式,兼容老程序就行了。速度至上。
364
386
  if ((0, type_predicate_2.isTyAnnTyParam)(leftTy) && !(0, type_predicate_2.isTyAnnTyParam)(rightTy)) {
365
- if ((0, type_predicate_2.isDecimalTy)(rightTy)) {
366
- env.unifier.unify(leftTy, type_manager_1.naslDecimalTy);
367
- }
368
- else if ((0, type_predicate_2.isIntegerTy)(rightTy)) {
369
- env.unifier.unify(type_manager_1.naslLongTy, leftTy);
370
- }
387
+ env.unifier.unify(type_manager_1.naslLongTy, leftTy);
371
388
  }
372
389
  else if (!(0, type_predicate_2.isTyAnnTyParam)(leftTy) && (0, type_predicate_2.isTyAnnTyParam)(rightTy)) {
373
- if ((0, type_predicate_2.isDecimalTy)(leftTy)) {
374
- env.unifier.unify(rightTy, type_manager_1.naslDecimalTy);
375
- }
376
- else if ((0, type_predicate_2.isIntegerTy)(leftTy)) {
377
- env.unifier.unify(type_manager_1.naslLongTy, rightTy);
378
- }
390
+ env.unifier.unify(type_manager_1.naslLongTy, rightTy);
379
391
  }
380
392
  // 人肉 solve
381
- const hasString = (0, type_predicate_2.isStringTy)(leftTy) || (0, type_predicate_2.isStringTy)(rightTy);
382
- const hasDecimal = (0, type_predicate_2.isDecimalTy)(leftTy) || (0, type_predicate_2.isDecimalTy)(rightTy);
383
- const hasLong = (0, type_predicate_2.isIntegerTy)(leftTy) || (0, type_predicate_2.isIntegerTy)(rightTy);
384
- if (nd.operator === '+' && hasString) {
385
- ndTy = type_manager_1.naslStringTy;
386
- }
387
- else if (nd.operator === '/') {
393
+ if (nd.operator === '/') { // 除法运算,结果必须是 decimal
388
394
  // 必须是 decimal
389
395
  ndTy = type_manager_1.naslDecimalTy;
390
396
  }
391
397
  else {
392
- if (hasDecimal) {
393
- ndTy = type_manager_1.naslDecimalTy;
394
- }
395
- else if (hasLong) {
396
- ndTy = type_manager_1.naslLongTy;
397
- }
398
- else {
399
- // 较大的类型
400
- ndTy = env.unifier.nextFreshTyAnn('free');
401
- env.unifier.unify(leftTy, ndTy);
402
- env.unifier.unify(rightTy, ndTy);
403
- }
398
+ // 较大的类型
399
+ ndTy = env.unifier.nextFreshTyAnn('free');
400
+ // 约束 ndTy 的上界为 Decimal
401
+ env.unifier.unify(ndTy, type_manager_1.naslDecimalTy);
402
+ // 约束 ndTy 的下界为 Long
403
+ env.unifier.unify(type_manager_1.naslLongTy, ndTy);
404
+ env.unifier.unify(leftTy, ndTy);
405
+ env.unifier.unify(rightTy, ndTy);
404
406
  }
405
407
  env.setType(nd, ndTy);
406
408
  env.unifier.unify(ndTy, tgtTy);
@@ -435,7 +437,7 @@ function tpBinaryExpression(env, nd, tgtTy) {
435
437
  return ty;
436
438
  if ((0, type_predicate_2.isMetadataType)(ty)) {
437
439
  // 使用typeAlias来查找元数据类型的底层类型
438
- const qName = (0, get_q_name_1.getTokenQualifiedName)(ty);
440
+ const qName = (0, def_key_helpers_1.getGlobalDefKey)(ty);
439
441
  if (qName && env.typeAlias.has(qName)) {
440
442
  return env.typeAlias.get(qName);
441
443
  }
@@ -506,10 +508,9 @@ function tpBinaryExpression(env, nd, tgtTy) {
506
508
  }
507
509
  case 'in': {
508
510
  const leftTy = dispatchExpr(env, nd.left, undefined);
509
- const rightTy = dispatchExpr(env, nd.right, undefined);
511
+ dispatchExpr(env, nd.right, (0, type_manager_1.createListTyAnn)(leftTy ?? type_manager_1.naslAnyTy));
510
512
  // T in List<T>
511
513
  env.setType(nd, type_manager_1.naslBooleanTy);
512
- env.unifier.unify((0, type_manager_1.createListTyAnn)(leftTy ?? type_manager_1.naslAnyTy), rightTy);
513
514
  env.unifier.unify(type_manager_1.naslBooleanTy, tgtTy);
514
515
  return type_manager_1.naslBooleanTy;
515
516
  }
@@ -644,7 +645,7 @@ const tpBinaryOrderExpr = (env, nd, tgtTy) => {
644
645
  if ((0, type_predicate_1.isUnionTy)(ty)) {
645
646
  return ty.typeArguments?.every(memberTy => isValidTy(memberTy)) ?? false;
646
647
  }
647
- const qName = (0, get_q_name_1.getTokenQualifiedName)(ty);
648
+ const qName = (0, def_key_helpers_1.getGlobalDefKey)(ty);
648
649
  return !!qName && env.typeAlias.has(qName);
649
650
  };
650
651
  // 不调用 solver 则无法判断,调用则影响速度,所以报错后移了
@@ -779,63 +780,92 @@ const tpAnonymousFunction = (env, nd, _tgtTy, isListSort = false) => {
779
780
  };
780
781
  exports.tpAnonymousFunction = tpAnonymousFunction;
781
782
  const tpSubLogic = (env, nd, tgtTy, isListSort = false) => {
782
- const subLogicVars = [...nd.params, ...nd.returns, ...nd.variables];
783
- env.refMgr.setLocalSymBindings(nd, subLogicVars);
784
- subLogicVars.forEach(v => (0, dispatch_def_1.dispatchDef)(env, v));
785
- // 处理 tgtTy 缺失的情况
786
- if (tgtTy && !(0, type_predicate_2.isFuncTy)(tgtTy) && !isListSort) {
787
- env.setType(nd, type_manager_1.naslAnyTy);
788
- env.addError((0, sem_diag_1.mkIncompatibleTyErr)(env, '函数', tgtTy));
789
- return (0, type_manager_1.createFnTyFromTyAnns)([], type_manager_1.naslAnyTy);
790
- }
791
- // 如果有 tgtTy 且是函数类型,则进行 unification
792
- if (tgtTy && (0, type_predicate_2.isFuncTy)(tgtTy)) {
793
- // TODO: 通过 default value 生成 constraints
794
- nd.params.forEach((param, idx) => {
795
- // v4.1 AI 相关需求要求它也能推
796
- const paramTy = env.getRawType(param);
797
- env.unifier.unifyContravariant(paramTy, tgtTy.typeArguments[idx], param); // contravariant
798
- });
799
- }
800
- // 若非前端,则 shallow copy,因为内部会触发 solve,会把进来前的约束清掉;
801
- // 若是前端,则无需 copy
802
- const csCopy = env.isView ? env.unifier.cs : new Map(env.unifier.cs);
803
- // 直接用 Solver 求解约束,并仅把求解结果代回到 SubLogic 的 params(避免 traverseSubstRunCheck 对 Identifier 的假设)
804
- if (!env.isView) {
805
- // 使用局部 Solver
806
- const localSolver = new solver_1.Solver(env);
807
- const subst = localSolver.simpleSolveConstraints();
808
- // 只替换 nd.params 上的类型变元
809
- const pSubst = (0, subster_1.inPlaceSubstTyAnn)(env, subst);
810
- for (const param of nd.params) {
811
- const rawTy = env.getRawType(param);
812
- if (rawTy) {
813
- const replaced = pSubst(rawTy);
814
- env.setType(param, replaced);
815
- }
783
+ return env.withPostCheckScope(() => {
784
+ // 保持与 tpAnonymousFunction 一致:先展开 expected function type 中的 tuple spread
785
+ const expectedTy = tgtTy ? desugarTupleSpreadInArgsOfFunctionType(tgtTy) : undefined;
786
+ // 仅对"表达式中的临时 SubLogic"(TS arrow-function block 解析产物)做参数类型的"预填充":
787
+ // - tpParam 直接用 expected type,而不是先生成 free type var
788
+ // - 保证闭包捕获变量(如外层 record 参数)具备正确成员类型,避免 Any 化
789
+ if (expectedTy && (0, type_predicate_2.isFuncTy)(expectedTy) && typeof nd.name === 'string' && nd.name.startsWith('$anon$')) {
790
+ nd.params.forEach((param, idx) => {
791
+ const exp = expectedTy.typeArguments?.[idx];
792
+ if (!exp)
793
+ return;
794
+ if (!param.typeAnnotation) {
795
+ param.typeAnnotation = (0, type_manager_1.copyTyAnn)(exp);
796
+ }
797
+ });
816
798
  }
817
- // 运行后置校验并把 postChecks 触发
818
- const normalizedSemTyMap = (0, subster_1.traverseAndSubst)(env)(nd, subst);
819
- const errs = localSolver.postCheckSolution(subst, localSolver.cs, normalizedSemTyMap) || [];
820
- if (errs.length > 0) {
821
- for (const err of errs) {
822
- env.addError(err.message, env.getCurFileNode(), err.errBoundary, err.fromPlayground ? 'warning' : 'error');
823
- }
799
+ const subLogicVars = [...nd.params, ...nd.returns, ...nd.variables];
800
+ env.refMgr.setLocalSymBindings(nd, subLogicVars);
801
+ subLogicVars.forEach(v => (0, dispatch_def_1.dispatchDef)(env, v));
802
+ // 处理 tgtTy 缺失的情况
803
+ if (expectedTy && !(0, type_predicate_2.isTyAnnTyParam)(expectedTy) && !(0, type_predicate_2.isFuncTy)(expectedTy) && !isListSort) {
804
+ env.setType(nd, type_manager_1.naslAnyTy);
805
+ env.addError((0, sem_diag_1.mkIncompatibleTyErr)(env, '函数', expectedTy));
806
+ return (0, type_manager_1.createFnTyFromTyAnns)([], type_manager_1.naslAnyTy);
807
+ }
808
+ // 如果有 tgtTy 且是函数类型,则进行 unification
809
+ if (expectedTy && (0, type_predicate_2.isFuncTy)(expectedTy)) {
810
+ // 对于“作为表达式出现的 SubLogic”(例如由 TS arrow-function block 生成),通常没有显式参数类型。
811
+ // 只做 contravariant unify 很难把参数类型从 expected type 传播进来,进而导致闭包捕获变量上的成员访问类型变成 Any。
812
+ // 因此:当参数未声明类型(或当前是 Any/未解),先用 expected param type 填充。
813
+ nd.params.forEach((param, idx) => {
814
+ const expected = expectedTy.typeArguments?.[idx];
815
+ if (!expected)
816
+ return;
817
+ const cur = env.getRawType(param);
818
+ if (!param.typeAnnotation && (!cur || (0, type_predicate_2.isAnyTy)(cur) || (0, type_predicate_1.isUnResolvedTy)(cur))) {
819
+ env.setType(param, expected);
820
+ }
821
+ });
822
+ // TODO: 通过 default value 生成 constraints
823
+ nd.params.forEach((param, idx) => {
824
+ // v4.1 AI 相关需求要求它也能推
825
+ const paramTy = env.getRawType(param);
826
+ env.unifier.unifyContravariant(paramTy, expectedTy.typeArguments[idx], param); // contravariant
827
+ });
824
828
  }
825
- env.runPostChecks(subst);
826
- }
827
- (0, dispatch_stmt_2.tpSolvingStmts)(env, nd.body);
828
- (0, dispatch_stmt_1.tpSolvingPlayground)(env, nd.playground);
829
- subLogicVars.forEach(env.removeLexicalSym);
830
- const ndTy = (0, type_manager_1.createRefTyAnnFromDef)(nd, env);
831
- if (tgtTy && ndTy.typeKind === 'function') {
832
- // expected type 上 copy sync 字段,保证 SubLogic 的函数类型和 Param 处声明的字段一致
833
- ndTy.sync = tgtTy.sync;
834
- }
835
- env.setType(nd, ndTy);
836
- env.unifier.cs = csCopy;
837
- !isListSort && env.unifier.unify(ndTy, tgtTy); // 这里需要额外的 unify,否则 SubLogic 算出来的类型不能与外侧进来时的约束产生关系
838
- return ndTy;
829
+ // 若非前端,则 shallow copy,因为内部会触发 solve,会把进来前的约束清掉;
830
+ // 若是前端,则无需 copy
831
+ const csCopy = env.isView ? env.unifier.cs : new Map(env.unifier.cs);
832
+ // 直接用 Solver 求解约束,并仅把求解结果代回到 SubLogic 的 params(避免 traverseSubstRunCheck 对 Identifier 的假设)
833
+ if (!env.isView) {
834
+ // 使用局部 Solver
835
+ const localSolver = new solver_1.Solver(env);
836
+ const subst = localSolver.simpleSolveConstraints();
837
+ // 只替换 nd.params 上的类型变元
838
+ const pSubst = (0, subster_1.inPlaceSubstTyAnn)(env, subst);
839
+ for (const param of nd.params) {
840
+ const rawTy = env.getRawType(param);
841
+ if (rawTy) {
842
+ const replaced = pSubst(rawTy);
843
+ env.setType(param, replaced);
844
+ }
845
+ }
846
+ // 运行后置校验并把 postChecks 触发
847
+ const normalizedSemTyMap = (0, subster_1.traverseAndSubst)(env)(nd, subst);
848
+ const errs = localSolver.postCheckSolution(subst, localSolver.cs, normalizedSemTyMap) || [];
849
+ if (!env.isErrorReportingDisabled() && !env.hasErrorDelegatee) {
850
+ for (const err of errs) {
851
+ env.addError(err.message, env.getCurFileNode(), err.errBoundary, err.fromPlayground ? 'warning' : 'error');
852
+ }
853
+ }
854
+ env.runPostChecks(subst);
855
+ }
856
+ (0, dispatch_stmt_2.tpSolvingStmts)(env, nd.body);
857
+ (0, dispatch_stmt_1.tpSolvingPlayground)(env, nd.playground);
858
+ subLogicVars.forEach(env.removeLexicalSym);
859
+ const ndTy = (0, type_manager_1.createRefTyAnnFromDef)(nd, env);
860
+ if (expectedTy && ndTy.typeKind === 'function') {
861
+ // 从 expected type 上 copy sync 字段,保证 SubLogic 的函数类型和 Param 处声明的字段一致
862
+ ndTy.sync = expectedTy.sync;
863
+ }
864
+ env.setType(nd, ndTy);
865
+ env.unifier.cs = csCopy;
866
+ !isListSort && env.unifier.unify(ndTy, expectedTy); // 这里需要额外的 unify,否则 SubLogic 算出来的类型不能与外侧进来时的约束产生关系
867
+ return ndTy;
868
+ });
839
869
  };
840
870
  exports.tpSubLogic = tpSubLogic;
841
871
  function tpArgument(env, nd, tgtTy) {
@@ -918,8 +948,9 @@ function tpCallQueryComponent(env, nd, tgtTy) {
918
948
  };
919
949
  env.ctxCQC = nd;
920
950
  env.ctxTpQFE = makeTpQueryFieldExpr;
951
+ const hasJoin = nd.from?.joinParts?.length > 0;
921
952
  // typing expressions in nd.from.joinsParts
922
- if (nd.from?.joinParts.length > 0) {
953
+ if (hasJoin) {
923
954
  tpJoinParts(env, nd.from.joinParts);
924
955
  }
925
956
  // this will also set aggrAsNames, groupByAsNames
@@ -1061,7 +1092,13 @@ function tpCallQueryComponent(env, nd, tgtTy) {
1061
1092
  return (0, type_manager_1.createAnonymousTyAnn)(selProps.map(string_1.lowercaseFirstChar), tyAnns);
1062
1093
  }
1063
1094
  });
1064
- retTy = (0, type_manager_1.createListTyAnn)((0, type_manager_1.createAnonymousTyAnn)(selShortNames.map(string_1.lowercaseFirstChar), tys));
1095
+ // 如果没有 join 且只有一个实体,直接返回该实体的类型,不包匿名结构
1096
+ if (nd.simplifyType && !hasJoin && selShortNames.length === 1) {
1097
+ retTy = (0, type_manager_1.createListTyAnn)(tys?.[0] || type_manager_1.naslAnyTy);
1098
+ }
1099
+ else {
1100
+ retTy = (0, type_manager_1.createListTyAnn)((0, type_manager_1.createAnonymousTyAnn)(selShortNames.map(string_1.lowercaseFirstChar), tys));
1101
+ }
1065
1102
  }
1066
1103
  // 2.11 之前才有,升级脚本也没管,需要特殊处理
1067
1104
  if (nd.limit) {
@@ -1138,6 +1175,7 @@ function tpCallQueryComponent(env, nd, tgtTy) {
1138
1175
  case 'COUNTD':
1139
1176
  return type_manager_1.naslLongTy;
1140
1177
  case 'AVG':
1178
+ env.unifier.unify(propTy, type_manager_1.naslDecimalOrLongTy);
1141
1179
  return type_manager_1.naslDecimalTy;
1142
1180
  default:
1143
1181
  return propTy;
@@ -1197,15 +1235,26 @@ function tpOqlQueryComponent(env, nd, tgtTy) {
1197
1235
  }
1198
1236
  const logicNd = parser.parseInLogicContext(`const $queryResult$ = ${code};`, '$queryResult$');
1199
1237
  if (logicNd) {
1200
- logicNd.name = 'test';
1201
- env.suppressErrorReporting();
1238
+ logicNd.parentNode = nd;
1239
+ logicNd.name = 'oqlTempLogic';
1240
+ env.setErrorDelegatee(nd);
1202
1241
  const oldCS = env.unifier.cs;
1203
1242
  // 对 dispatchDef 的调用,会修改 env.unifier.cs。因此需要给他一个全新的cs,避免污染正常的cs
1204
1243
  const newCS = new Map();
1205
1244
  env.unifier.cs = newCS;
1206
- (0, dispatch_def_1.dispatchDef)(env, logicNd);
1207
- env.unifier.cs = oldCS;
1208
- env.enableErrorReporting();
1245
+ try {
1246
+ (0, dispatch_def_1.tpLogic)(env, logicNd);
1247
+ }
1248
+ catch (err) {
1249
+ // 打印下错误,便于排查
1250
+ env.logger?.fatal?.('[tpOqlQueryComponent] error:', err);
1251
+ }
1252
+ finally {
1253
+ // @ts-expect-error
1254
+ logicNd.parentNode = null;
1255
+ env.unifier.cs = oldCS;
1256
+ env.resetErrorDelegatee();
1257
+ }
1209
1258
  if (nd.typeAnnotation) {
1210
1259
  // 有类型标注,直接用
1211
1260
  env.setType(nd, nd.typeAnnotation);
@@ -1286,17 +1335,19 @@ function tpNewComposite(env, nd, tgtTy) {
1286
1335
  if (right && (0, nasl_type_manipulation_1.isEnumIdentifier)(right)) {
1287
1336
  env.addError(`新建表达式中 ${right.toNaturalTS()} 枚举类不能直接使用,请取它的枚举项`, undefined, right);
1288
1337
  }
1289
- env.unifier.unifyWithBoundary(rTy, lPropTyAnn, right);
1338
+ // 传递当前这条连线,以便在错误报告中记录是哪条连线导致的错误
1339
+ const context = { assignmentLine: line };
1340
+ env.unifier.unifyWithBoundary(rTy, lPropTyAnn, right, context);
1290
1341
  });
1291
1342
  const properties = toRaws(nd.properties);
1292
1343
  // 没连线的左边的元素们。其实无所谓,但要跟现在保持一致。
1293
1344
  properties.forEach((pIdent) => {
1294
1345
  if (!env.typeBindings.get(pIdent)) {
1295
1346
  let lPropTyAnn = lNameTyPair.find(([name, _]) => name === pIdent.name)?.[1];
1296
- // setType 应该够了,直接 dispatchExpr 会因为 pIdent 没有加到 env.lexicalVarStacks 里,导致找不到而报错
1347
+ // setType 应该够了,直接 dispatchExpr 会因为 pIdent 没有加到 env.localDefStacks 里,导致找不到而报错
1297
1348
  if (!lPropTyAnn) {
1298
1349
  if (nd.typeAnnotation?.typeKind === 'anonymousStructure') {
1299
- lPropTyAnn = type_manager_1.naslStringTy;
1350
+ lPropTyAnn = tgtTy?.properties?.find((p) => p.name === pIdent.name)?.typeAnnotation ?? type_manager_1.naslStringTy;
1300
1351
  }
1301
1352
  else {
1302
1353
  lPropTyAnn = env.unifier.nextFreshTyAnn('free');
@@ -1330,7 +1381,7 @@ const extractNameTyPair = (env, ty) => {
1330
1381
  return ty.properties.map((p, _) => [p.name, p.typeAnnotation]);
1331
1382
  }
1332
1383
  else if (ty) {
1333
- return (0, fp_macros_1.IfBind)((0, get_q_name_1.getTokenQualifiedName)(ty))(qName => env.refMgr.gQNameDefs.get(qName)
1384
+ return (0, fp_macros_1.IfBind)((0, def_key_helpers_1.getGlobalDefKey)(ty))(qName => env.refMgr.gQNameDefs.get(qName)
1334
1385
  ?.properties
1335
1386
  .map((p, _) => [p.name, p.typeAnnotation ?? null]))((0, fp_macros_1.feed)([]));
1336
1387
  }
@@ -1354,11 +1405,17 @@ function tpNewList(env, nd, tgtTy) {
1354
1405
  env.setType(nd, nd.typeAnnotation);
1355
1406
  }
1356
1407
  else {
1357
- const itemTys = toRaws(nd.items).map(item => dispatchExpr(env, item, undefined)).filter(Boolean);
1358
- const itemUnionTy = (0, type_manager_1.createUnionTyAnnIfNecessary)(env, itemTys);
1408
+ const isTgtTyLegal = (0, type_predicate_2.isListTy)(tgtTy);
1409
+ const itemTys = toRaws(nd.items).map(item => dispatchExpr(env, item, undefined)).filter((ty) => {
1410
+ if (!ty)
1411
+ return false;
1412
+ return !isTgtTyLegal || !(0, type_predicate_2.isAnyTy)(ty);
1413
+ });
1414
+ // 页面下是延迟求解的,此处如果加上合法性判断,会导致从左到右的推导失效
1415
+ const itemUnionTy = !itemTys.length ? env.unifier.nextFreshTyAnn('free') : (0, type_manager_1.createUnionTyAnnIfNecessary)(env, itemTys);
1359
1416
  const listTy = (0, type_manager_1.createListTyAnn)(itemUnionTy);
1360
1417
  // TODO: 不精确的检查,如果 tgtTy 是 A | List<T>,则会走到下一个分支,就没要求 invariance 了,以后再修吧
1361
- if ((0, type_predicate_2.isListTy)(tgtTy)) {
1418
+ if (isTgtTyLegal) {
1362
1419
  const tgtItemTy = tgtTy.typeArguments?.[0];
1363
1420
  env.unifier.unifyEq(itemUnionTy, tgtItemTy);
1364
1421
  }
@@ -1409,18 +1466,36 @@ function tpNewMap(env, nd, tgtTy) {
1409
1466
  return nd.typeAnnotation;
1410
1467
  }
1411
1468
  else {
1412
- const valFv = env.unifier.nextFreshTyAnn('free');
1469
+ const isTgtTyLegal = (0, type_predicate_2.isMapTy)(tgtTy);
1470
+ let tgtKeyTy = undefined;
1471
+ let tgtValTy = undefined;
1472
+ if (isTgtTyLegal) {
1473
+ tgtKeyTy = tgtTy?.typeArguments?.[0];
1474
+ tgtValTy = tgtTy?.typeArguments?.[1];
1475
+ }
1413
1476
  const keys = toRaws(nd.keys);
1414
1477
  const firstKeyTy = dispatchExpr(env, keys[0], undefined);
1478
+ const hasFirstKeyTy = firstKeyTy && !(0, type_predicate_2.isAnyTy)(firstKeyTy);
1479
+ // 页面下是延迟求解的,如果没有推导出 key 类型,使用 fresh type variable
1480
+ const keyTy = hasFirstKeyTy ? firstKeyTy : tgtKeyTy ?? env.unifier.nextFreshTyAnn('free');
1415
1481
  for (let i = 1; i < keys.length; i++) {
1416
- dispatchExpr(env, keys[i], firstKeyTy); // 内部会产生类型不匹配的报错
1482
+ dispatchExpr(env, keys[i], keyTy); // 内部会产生类型不匹配的报错
1417
1483
  }
1418
1484
  // 规定:key 类型不能是 union。仅 value 类型可以是 union。
1419
- const valTys = toRaws(nd.values).map(value => dispatchExpr(env, value, undefined)).filter(Boolean);
1420
- const valUnionTys = (0, type_manager_1.createUnionTyAnnIfNecessary)(env, valTys);
1485
+ const valTys = toRaws(nd.values).map(value => dispatchExpr(env, value, undefined)).filter((ty) => {
1486
+ if (!ty)
1487
+ return false;
1488
+ return !isTgtTyLegal || !(0, type_predicate_2.isAnyTy)(ty);
1489
+ });
1490
+ const hasValTy = valTys.length > 0;
1491
+ const valUnionTys = hasValTy ? (0, type_manager_1.createUnionTyAnnIfNecessary)(env, valTys) : tgtValTy ?? type_manager_1.naslAnyTy;
1492
+ // 都是“indexedAccess”的情况,需要用 fresh 类型去约束
1493
+ const valFv = env.unifier.nextFreshTyAnn('free');
1421
1494
  env.unifier.unify(valUnionTys, valFv);
1422
- const mapTy = (0, type_manager_1.createMapTyAnn)(firstKeyTy ?? type_manager_1.naslAnyTy, valFv);
1423
- env.unifier.unify(mapTy, tgtTy);
1495
+ const mapTy = (0, type_manager_1.createMapTyAnn)(keyTy, valFv);
1496
+ if (hasFirstKeyTy || hasValTy) {
1497
+ env.unifier.unify(mapTy, tgtTy);
1498
+ }
1424
1499
  env.setType(nd, mapTy);
1425
1500
  return mapTy;
1426
1501
  }
@@ -1446,6 +1521,8 @@ function tpMatch(env, nd, tgtTy) {
1446
1521
  const exprTy = nd.isExpression ?
1447
1522
  dispatchExpr(env, nd.expression, undefined) :
1448
1523
  tpSolvingExpr(env, nd.expression, undefined);
1524
+ // 类型匹配,必须加上isTypeMatch 判断,否则值匹配时会错误地用值的类型去约束未解析类型,类型细化也将基于错误的类型
1525
+ const isTypeMatch = nd.cases.some(caseItem => caseItem.patterns.length > 0 && caseItem.patterns.every((p) => (0, type_predicate_1.isTypeAnnotation)(p)));
1449
1526
  const tpMatchTypeRefineCase = (nd, exprTy) => (mc) => {
1450
1527
  let exprRefinedTy = exprTy;
1451
1528
  // mc.patterns 中可能包含类型模式和值模式,分别对应类型匹配和值匹配。
@@ -1469,14 +1546,32 @@ function tpMatch(env, nd, tgtTy) {
1469
1546
  const prevPatterns = prevCases.flatMap((pc) => pc.patterns);
1470
1547
  const pureTys = prevPatterns.filter((x) => (0, type_predicate_1.isTypeAnnotation)(x));
1471
1548
  // 确保我们在处理纯类型的匹配。值匹配不用任何精化。
1472
- if (pureTys.length === prevPatterns.length) {
1473
- const caseRefinedTys = (0, type_predicate_1.isUnionTy)(exprTy)
1474
- ? exprTy?.typeArguments?.filter((t1) => !pureTys.find((t2) => (0, type_predicate_1.isEqualTy)(env, t1, t2)))
1475
- : [];
1476
- if (caseRefinedTys?.length) {
1477
- exprRefinedTy = (0, type_manager_1.createUnionTyAnnIfNecessary)(env, caseRefinedTys); // TODO 报错
1549
+ if (pureTys.length === prevPatterns.length && pureTys.length > 0) {
1550
+ if ((0, type_predicate_1.isUnionTy)(exprTy)) {
1551
+ // exprTy union 类型,直接计算差集
1552
+ const caseRefinedTys = exprTy?.typeArguments?.filter((t1) => !pureTys.find((t2) => (0, type_predicate_1.isEqualTy)(env, t1, t2)));
1553
+ if (caseRefinedTys?.length) {
1554
+ exprRefinedTy = (0, type_manager_1.createUnionTyAnnIfNecessary)(env, caseRefinedTys);
1555
+ }
1556
+ }
1557
+ else {
1558
+ // exprTy 不是 union 类型(可能是类型参数),创建 Exclude 代类型延迟求解
1559
+ const excludedUnion = (0, type_manager_1.createUnionTyAnnIfNecessary)(env, pureTys);
1560
+ exprRefinedTy = nasl_concepts_1.TypeAnnotation.createProtoTypeOnly({
1561
+ typeKind: 'generic',
1562
+ typeName: 'Exclude',
1563
+ typeArguments: [exprTy, excludedUnion],
1564
+ });
1478
1565
  }
1479
1566
  }
1567
+ // 值匹配
1568
+ if (!isTypeMatch) {
1569
+ toRaws(mc.patterns).forEach(pattern => {
1570
+ env.withPostCheckScope(() => {
1571
+ tpSolvingExpr(env, pattern, exprRefinedTy);
1572
+ });
1573
+ });
1574
+ }
1480
1575
  }
1481
1576
  const allocatedVars = new Set();
1482
1577
  const itVar = nasl_concepts_1.Variable.createProtoTypeOnly({
@@ -1486,9 +1581,9 @@ function tpMatch(env, nd, tgtTy) {
1486
1581
  }); // 新加的每个分支里的 'it' 变量
1487
1582
  allocatedVars.add(itVar);
1488
1583
  let matchedVarName = undefined;
1489
- const isRefined = shouldRefineType(nd.expression, exprTy);
1584
+ const isRefined = shouldRefineType(nd.expression, isTypeMatch);
1490
1585
  if (isRefined) {
1491
- matchedVarName = (0, get_q_name_1.getTokenQualifiedNameForMatchedExpr)(env, nd.expression);
1586
+ matchedVarName = (0, def_key_helpers_1.getGlobalDefKeyForMatchedExpr)(env, nd.expression);
1492
1587
  const freshMatchedVar = nasl_concepts_1.Variable.createProtoTypeOnly({
1493
1588
  name: matchedVarName,
1494
1589
  typeAnnotation: exprRefinedTy,
@@ -1521,30 +1616,7 @@ function tpMatch(env, nd, tgtTy) {
1521
1616
  }
1522
1617
  };
1523
1618
  if (exprTy) {
1524
- for (const cs of nd.cases) {
1525
- for (const p of cs.patterns) {
1526
- if (!(0, type_predicate_1.isTypeAnnotation)(p)) {
1527
- dispatchExpr(env, p, undefined);
1528
- }
1529
- }
1530
- }
1531
- // 类型匹配,必须加上isTypeMatch 判断,否则值匹配时会错误地用值的类型去约束未解析类型,类型细化也将基于错误的类型
1532
- const isTypeMatch = nd.cases.some((caseItem) => {
1533
- return caseItem.patterns.length > 0 && caseItem.patterns.every((p) => (0, type_predicate_1.isTypeAnnotation)(p));
1534
- });
1535
- // 只有当 exprTy 是未解析的类型(typeParam 或 indexedAccess)时,才需要从 patterns 构造 union 类型来约束它
1536
- if (isTypeMatch && ((0, type_predicate_2.isTyAnnTyParam)(exprTy) || (0, type_predicate_1.isIndexedType)(exprTy))) {
1537
- // 从已有的 match cases 的类型构造出 union-like type
1538
- const patTys = nd.cases.flatMap(c => c.patterns).map(getPatTy).filter(types_1.isNotNil);
1539
- for (const pTy of patTys) {
1540
- env.unifier.unify(pTy, exprTy); // 各个分支的类型的 union <: 类型变元
1541
- }
1542
- const unionTy = (0, type_manager_1.createUnionTyAnnIfNecessary)(env, patTys);
1543
- handleMatchingAgainstTypes(unionTy);
1544
- }
1545
- else { // 如果 exprTy 已经是确定的类型(包括 union 类型),直接使用 exprTy 即可
1546
- handleMatchingAgainstTypes(exprTy);
1547
- }
1619
+ handleMatchingAgainstTypes(exprTy);
1548
1620
  }
1549
1621
  // mark the type of the whole match construct
1550
1622
  if (nd.isExpression) {
@@ -1559,8 +1631,8 @@ function tpMatch(env, nd, tgtTy) {
1559
1631
  env.setType(nd, type_manager_1.naslVoidTy);
1560
1632
  }
1561
1633
  return env.getRawType(nd);
1562
- function handleMatchingAgainstTypes(unionTy) {
1563
- nd.cases.forEach(tpMatchTypeRefineCase(nd, unionTy));
1634
+ function handleMatchingAgainstTypes(exprTy) {
1635
+ nd.cases.forEach(tpMatchTypeRefineCase(nd, exprTy));
1564
1636
  }
1565
1637
  function getPatTy(x) {
1566
1638
  if ((0, type_predicate_1.isTypeAnnotation)(x)) {
@@ -1570,14 +1642,23 @@ function tpMatch(env, nd, tgtTy) {
1570
1642
  // 这不仅引人深思:为什么 1 的类型就不能随着上下文变化呢,而要 argument: Decimal argument.expr : Long
1571
1643
  // 那好了,match 这里其实是又要特殊处理的
1572
1644
  }
1573
- function shouldRefineType(nd, exprRefinedTy) {
1645
+ function shouldRefineType(nd, isTypeMatch) {
1574
1646
  const validExpr = nd.concept === 'Identifier' || nd.concept === 'MemberExpression';
1575
- // 仅当输入是 union 类型或可以实例化为 union 类型的类型变元才进行 type refinement
1576
- const validTy = (0, type_predicate_1.isUnionTy)(exprRefinedTy) || (0, type_predicate_2.isTyAnnTyParam)(exprRefinedTy);
1577
- return validExpr && validTy;
1647
+ return validExpr && isTypeMatch;
1578
1648
  }
1579
1649
  }
1580
1650
  exports.tpMatch = tpMatch;
1651
+ function tpIfExpression(env, nd, tgtTy) {
1652
+ const conditionTy = dispatchExpr(env, nd.condition, type_manager_1.naslBooleanTy);
1653
+ env.unifier.unify(conditionTy, type_manager_1.naslBooleanTy);
1654
+ const consequentTy = dispatchExpr(env, nd.consequent, undefined);
1655
+ const alternateTy = dispatchExpr(env, nd.alternate, undefined);
1656
+ const ifTy = (0, type_manager_1.createUnionTyAnnIfNecessary)(env, [consequentTy, alternateTy].filter(e => Boolean(e) && !(0, type_predicate_2.isAnyTy)(e)));
1657
+ env.setType(nd, ifTy);
1658
+ env.unifier.unify(ifTy, tgtTy);
1659
+ return ifTy;
1660
+ }
1661
+ exports.tpIfExpression = tpIfExpression;
1581
1662
  function tpUnparsed(env, nd, tgtTy) {
1582
1663
  // should be bottom type,但是现在没有 bottom type 怎么办?
1583
1664
  // 按后端设成 string 的话前端各种骚用法会报错什么 [1, 2, 3] 这种,难道你要我 typeof eval(nd)?
@@ -1634,7 +1715,7 @@ function desugarAsCalling(env, originNd, qName, args) {
1634
1715
  const copied = (0, type_manager_1.copyTyAnn)(funcTy);
1635
1716
  // 首先展开函数类型,将spread参数转换为具体的参数列表
1636
1717
  const expandedFuncTy = expandFunctionTypeWithSpread(copied, args.length);
1637
- const expandedParams = extractParamsFromFunctionType(expandedFuncTy);
1718
+ const expandedParams = (0, dispatch_call_1.extractParamsFromFunctionType)(expandedFuncTy);
1638
1719
  if (!expandedParams) {
1639
1720
  // 预期不会走到这里
1640
1721
  return;
@@ -1681,7 +1762,7 @@ function desugarAsCalling(env, originNd, qName, args) {
1681
1762
  if (!funcTy || funcTy.typeKind !== 'function') {
1682
1763
  return funcTy;
1683
1764
  }
1684
- const params = extractParamsFromFunctionType(funcTy);
1765
+ const params = (0, dispatch_call_1.extractParamsFromFunctionType)(funcTy);
1685
1766
  if (!params) {
1686
1767
  return funcTy;
1687
1768
  }
@@ -1729,46 +1810,6 @@ function desugarAsCalling(env, originNd, qName, args) {
1729
1810
  }
1730
1811
  return expandedFuncTy;
1731
1812
  }
1732
- // TODO 考虑和dispatch-call里面的同名函数合并一下
1733
- /**
1734
- * 从函数类型中提取参数定义信息
1735
- *
1736
- * 这个函数解决了局部变量方法调用时无法获取参数定义(def)的问题。
1737
- * 通过分析函数类型的fnArgs和typeArguments,重构出Param对象,
1738
- * 使得可以正确判断参数是否为spread类型。
1739
- *
1740
- * @param fnTy 函数类型
1741
- * @returns 参数定义数组,包含name、typeAnnotation、spread等信息
1742
- */
1743
- function extractParamsFromFunctionType(fnTy) {
1744
- if (!(0, type_predicate_2.isFuncTy)(fnTy)) {
1745
- return undefined;
1746
- }
1747
- const params = [];
1748
- // 优先从fnArgs中提取参数信息,因为它包含参数名
1749
- if (fnTy.fnArgs && fnTy.fnArgs.length > 0) {
1750
- fnTy.fnArgs.forEach((arg, index) => {
1751
- const param = nasl_concepts_1.Param.createProtoTypeOnly({
1752
- name: arg.name || `param${index + 1}`,
1753
- typeAnnotation: arg.type,
1754
- spread: arg.spread,
1755
- });
1756
- params.push(param);
1757
- });
1758
- }
1759
- else if (fnTy.typeArguments && fnTy.typeArguments.length > 0) {
1760
- // 如果没有fnArgs,从typeArguments中提取
1761
- fnTy.typeArguments.forEach((argType, index) => {
1762
- const param = nasl_concepts_1.Param.createProtoTypeOnly({
1763
- name: `param${index + 1}`, // 默认参数名
1764
- typeAnnotation: argType,
1765
- spread: argType.spread
1766
- });
1767
- params.push(param);
1768
- });
1769
- }
1770
- return params;
1771
- }
1772
1813
  }
1773
1814
  function tpNewRegex(env, nd, tgtTy) {
1774
1815
  // 我们将对NewRegex的类型检查归约为对nasl.util.NewRegex(nd.pattern, nd.flags)的类型检查