kopscript 0.7.2 → 0.9.0

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.
package/dist/checker.js CHANGED
@@ -221,7 +221,7 @@ export class Checker {
221
221
  this.externValues.set(decl.name, T.STRING);
222
222
  const resolvedPath = resolve(dirname(this.currentFilePath), decl.path);
223
223
  if (!existsSync(resolvedPath)) {
224
- this.diagnostics.error(`Cannot find file '${decl.path}' referenced by 'raw string ${decl.name}' (looked for '${resolvedPath}')`, decl.line, decl.col);
224
+ this.diagnostics.error("KS4001", `Cannot find file '${decl.path}' referenced by 'raw string ${decl.name}' (looked for '${resolvedPath}')`, decl.line, decl.col);
225
225
  return;
226
226
  }
227
227
  this.rawContents.set(decl.name, readFileSync(resolvedPath, "utf-8"));
@@ -272,10 +272,10 @@ export class Checker {
272
272
  const seen = new Map();
273
273
  const declare = (name, line, col) => {
274
274
  if (this.importedNames.has(name)) {
275
- this.diagnostics.error(`Declaration '${name}' conflicts with a name brought in by 'using'`, line, col);
275
+ this.diagnostics.error("KS4002", `Declaration '${name}' conflicts with a name brought in by 'using'`, line, col);
276
276
  }
277
277
  else if (seen.has(name)) {
278
- this.diagnostics.error(`Duplicate top-level declaration '${name}'`, line, col);
278
+ this.diagnostics.error("KS4003", `Duplicate top-level declaration '${name}'`, line, col);
279
279
  }
280
280
  seen.set(name, true);
281
281
  };
@@ -305,11 +305,11 @@ export class Checker {
305
305
  return;
306
306
  const info = this.classes.get(decl.name);
307
307
  if (info.superclass && !this.isExportedName(info.superclass)) {
308
- this.diagnostics.error(`Exported class '${decl.name}' has a base class '${info.superclass}' that isn't exported`, decl.line, decl.col);
308
+ this.diagnostics.error("KS4004", `Exported class '${decl.name}' has a base class '${info.superclass}' that isn't exported`, decl.line, decl.col);
309
309
  }
310
310
  for (const ifaceName of info.interfaces) {
311
311
  if (!this.isExportedName(ifaceName)) {
312
- this.diagnostics.error(`Exported class '${decl.name}' implements interface '${ifaceName}', which isn't exported`, decl.line, decl.col);
312
+ this.diagnostics.error("KS4005", `Exported class '${decl.name}' implements interface '${ifaceName}', which isn't exported`, decl.line, decl.col);
313
313
  }
314
314
  }
315
315
  }
@@ -321,7 +321,7 @@ export class Checker {
321
321
  return;
322
322
  for (const baseName of info.bases) {
323
323
  if (!this.isExportedName(baseName)) {
324
- this.diagnostics.error(`Exported interface '${decl.name}' extends interface '${baseName}', which isn't exported`, decl.line, decl.col);
324
+ this.diagnostics.error("KS4006", `Exported interface '${decl.name}' extends interface '${baseName}', which isn't exported`, decl.line, decl.col);
325
325
  }
326
326
  }
327
327
  }
@@ -342,10 +342,10 @@ export class Checker {
342
342
  if (!resolved) {
343
343
  const name = node.kind === "NamedType" ? node.name : "[]";
344
344
  if (name !== "[]" && this.genericTypeParams.has(name) && !node.typeArgs) {
345
- this.diagnostics.error(`Generic type '${name}' requires a type argument (e.g. '${name}<T>')`, line, col);
345
+ this.diagnostics.error("KS4007", `Generic type '${name}' requires a type argument (e.g. '${name}<T>')`, line, col);
346
346
  }
347
347
  else {
348
- this.diagnostics.error(`Unknown type '${name}'`, line, col);
348
+ this.diagnostics.error("KS4008", `Unknown type '${name}'`, line, col);
349
349
  }
350
350
  return T.UNKNOWN;
351
351
  }
@@ -380,10 +380,10 @@ export class Checker {
380
380
  case "interface": {
381
381
  const isGeneric = this.genericTypeParams.has(type.name);
382
382
  if (isGeneric && !type.typeArg) {
383
- this.diagnostics.error(`Generic type '${type.name}' requires a type argument (e.g. '${type.name}<T>')`, line, col);
383
+ this.diagnostics.error("KS4009", `Generic type '${type.name}' requires a type argument (e.g. '${type.name}<T>')`, line, col);
384
384
  }
385
385
  else if (!isGeneric && type.typeArg) {
386
- this.diagnostics.error(`Type '${type.name}' is not generic — it doesn't take a type argument`, line, col);
386
+ this.diagnostics.error("KS4010", `Type '${type.name}' is not generic — it doesn't take a type argument`, line, col);
387
387
  }
388
388
  if (type.typeArg)
389
389
  this.validateGenericArity(type.typeArg, line, col);
@@ -450,7 +450,7 @@ export class Checker {
450
450
  const members = new Map();
451
451
  decl.members.forEach((name, index) => {
452
452
  if (members.has(name)) {
453
- this.diagnostics.error(`Duplicate enum member '${name}'`, decl.line, decl.col);
453
+ this.diagnostics.error("KS4011", `Duplicate enum member '${name}'`, decl.line, decl.col);
454
454
  return;
455
455
  }
456
456
  members.set(name, index);
@@ -468,14 +468,14 @@ export class Checker {
468
468
  const bases = [];
469
469
  for (const baseName of decl.baseList) {
470
470
  if (this.namedTypes.get(baseName) !== "interface") {
471
- this.diagnostics.error(`Interface '${decl.name}' can only extend other interfaces (unknown interface '${baseName}')`, decl.line, decl.col);
471
+ this.diagnostics.error("KS4012", `Interface '${decl.name}' can only extend other interfaces (unknown interface '${baseName}')`, decl.line, decl.col);
472
472
  continue;
473
473
  }
474
474
  // v1 generics can't appear in a base list at all — only as a
475
475
  // standalone type (field/param/return/local, `new Box<T>()`). A
476
476
  // class/interface always implements/extends a *bare* name.
477
477
  if (this.genericTypeParams.has(baseName)) {
478
- this.diagnostics.error(`Interface '${decl.name}' cannot extend generic interface '${baseName}' — not supported in v1`, decl.line, decl.col);
478
+ this.diagnostics.error("KS4013", `Interface '${decl.name}' cannot extend generic interface '${baseName}' — not supported in v1`, decl.line, decl.col);
479
479
  continue;
480
480
  }
481
481
  bases.push(baseName);
@@ -492,7 +492,7 @@ export class Checker {
492
492
  while (stack.length > 0) {
493
493
  const current = stack.pop();
494
494
  if (current === decl.name) {
495
- this.diagnostics.error(`Circular interface inheritance detected involving '${decl.name}'`, decl.line, decl.col);
495
+ this.diagnostics.error("KS4014", `Circular interface inheritance detected involving '${decl.name}'`, decl.line, decl.col);
496
496
  return;
497
497
  }
498
498
  if (seen.has(current))
@@ -563,13 +563,13 @@ export class Checker {
563
563
  // standalone type (field/param/return/local, `new Box<T>()`). A
564
564
  // class always extends/implements a *bare* name.
565
565
  if (this.genericTypeParams.has(baseName)) {
566
- this.diagnostics.error(`Class '${decl.name}' cannot extend/implement generic type '${baseName}' — not supported in v1`, decl.line, decl.col);
566
+ this.diagnostics.error("KS4015", `Class '${decl.name}' cannot extend/implement generic type '${baseName}' — not supported in v1`, decl.line, decl.col);
567
567
  continue;
568
568
  }
569
569
  const kind = this.namedTypes.get(baseName);
570
570
  if (kind === "class") {
571
571
  if (superclass !== null) {
572
- this.diagnostics.error(`Class '${decl.name}' cannot extend multiple classes ('${superclass}' and '${baseName}')`, decl.line, decl.col);
572
+ this.diagnostics.error("KS4016", `Class '${decl.name}' cannot extend multiple classes ('${superclass}' and '${baseName}')`, decl.line, decl.col);
573
573
  }
574
574
  else {
575
575
  superclass = baseName;
@@ -579,7 +579,7 @@ export class Checker {
579
579
  interfaces.push(baseName);
580
580
  }
581
581
  else {
582
- this.diagnostics.error(`Unknown base class or interface '${baseName}'`, decl.line, decl.col);
582
+ this.diagnostics.error("KS4017", `Unknown base class or interface '${baseName}'`, decl.line, decl.col);
583
583
  }
584
584
  }
585
585
  this.classes.set(decl.name, {
@@ -602,7 +602,7 @@ export class Checker {
602
602
  let current = info.superclass;
603
603
  while (current) {
604
604
  if (seen.has(current)) {
605
- this.diagnostics.error(`Circular inheritance detected involving '${decl.name}'`, decl.line, decl.col);
605
+ this.diagnostics.error("KS4018", `Circular inheritance detected involving '${decl.name}'`, decl.line, decl.col);
606
606
  return;
607
607
  }
608
608
  seen.add(current);
@@ -617,11 +617,11 @@ export class Checker {
617
617
  return;
618
618
  if (info.superclass) {
619
619
  if (!decl.constructor.baseArgs) {
620
- this.diagnostics.error(`Class '${decl.name}' extends '${info.superclass}' and must call the base constructor via ': base(...)'`, decl.constructor.line, decl.constructor.col);
620
+ this.diagnostics.error("KS4019", `Class '${decl.name}' extends '${info.superclass}' and must call the base constructor via ': base(...)'`, decl.constructor.line, decl.constructor.col);
621
621
  }
622
622
  }
623
623
  else if (decl.constructor.baseArgs) {
624
- this.diagnostics.error(`Class '${decl.name}' has no base class; ': base(...)' is not valid here`, decl.constructor.line, decl.constructor.col);
624
+ this.diagnostics.error("KS4020", `Class '${decl.name}' has no base class; ': base(...)' is not valid here`, decl.constructor.line, decl.constructor.col);
625
625
  }
626
626
  }
627
627
  // Walks up the inheritance chain to find the nearest ancestor that already
@@ -644,28 +644,28 @@ export class Checker {
644
644
  continue; // static methods don't participate in virtual dispatch
645
645
  const methodInfo = classInfo.methods.get(method.name);
646
646
  if (methodInfo.isVirtual && methodInfo.isOverride) {
647
- this.diagnostics.error(`Method '${method.name}' cannot be both 'virtual' and 'override'`, method.line, method.col);
647
+ this.diagnostics.error("KS4021", `Method '${method.name}' cannot be both 'virtual' and 'override'`, method.line, method.col);
648
648
  }
649
649
  const ancestor = this.findNearestMethodInChain(decl.name, method.name);
650
650
  if (ancestor) {
651
651
  const overridable = ancestor.info.isVirtual || ancestor.info.isOverride;
652
652
  if (!methodInfo.isOverride) {
653
- this.diagnostics.error(`Method '${method.name}' hides inherited member '${ancestor.owner}.${method.name}'; add 'override' (and mark the base member 'virtual')`, method.line, method.col);
653
+ this.diagnostics.error("KS4022", `Method '${method.name}' hides inherited member '${ancestor.owner}.${method.name}'; add 'override' (and mark the base member 'virtual')`, method.line, method.col);
654
654
  }
655
655
  else if (!overridable) {
656
- this.diagnostics.error(`Cannot override non-virtual method '${ancestor.owner}.${method.name}'; mark it 'virtual' in '${ancestor.owner}'`, method.line, method.col);
656
+ this.diagnostics.error("KS4023", `Cannot override non-virtual method '${ancestor.owner}.${method.name}'; mark it 'virtual' in '${ancestor.owner}'`, method.line, method.col);
657
657
  }
658
658
  else {
659
659
  const paramsMatch = methodInfo.params.length === ancestor.info.params.length &&
660
660
  methodInfo.params.every((p, i) => T.typesEqual(p, ancestor.info.params[i]));
661
661
  const returnMatches = T.typesEqual(methodInfo.returnType, ancestor.info.returnType);
662
662
  if (!paramsMatch || !returnMatches) {
663
- this.diagnostics.error(`Method '${method.name}' does not match the signature of overridden method '${ancestor.owner}.${method.name}'`, method.line, method.col);
663
+ this.diagnostics.error("KS4024", `Method '${method.name}' does not match the signature of overridden method '${ancestor.owner}.${method.name}'`, method.line, method.col);
664
664
  }
665
665
  }
666
666
  }
667
667
  else if (methodInfo.isOverride) {
668
- this.diagnostics.error(`Method '${method.name}' marked 'override' but no matching method was found in a base class`, method.line, method.col);
668
+ this.diagnostics.error("KS4025", `Method '${method.name}' marked 'override' but no matching method was found in a base class`, method.line, method.col);
669
669
  }
670
670
  }
671
671
  }
@@ -677,12 +677,12 @@ export class Checker {
677
677
  for (const sig of this.collectInterfaceMethods(ifaceName)) {
678
678
  const found = this.lookupMethod(decl.name, sig.name);
679
679
  if (!found) {
680
- this.diagnostics.error(`Class '${decl.name}' does not implement method '${sig.name}' required by interface '${ifaceName}'`, decl.line, decl.col);
680
+ this.diagnostics.error("KS4026", `Class '${decl.name}' does not implement method '${sig.name}' required by interface '${ifaceName}'`, decl.line, decl.col);
681
681
  continue;
682
682
  }
683
683
  const paramsMatch = found.info.params.length === sig.params.length && found.info.params.every((p, i) => T.typesEqual(p, sig.params[i]));
684
684
  if (!paramsMatch || !T.typesEqual(found.info.returnType, sig.returnType)) {
685
- this.diagnostics.error(`Class '${decl.name}' member '${sig.name}' does not match the signature required by interface '${ifaceName}'`, decl.line, decl.col);
685
+ this.diagnostics.error("KS4027", `Class '${decl.name}' member '${sig.name}' does not match the signature required by interface '${ifaceName}'`, decl.line, decl.col);
686
686
  }
687
687
  }
688
688
  }
@@ -772,13 +772,13 @@ export class Checker {
772
772
  return;
773
773
  if (visibility === "private") {
774
774
  if (ctx.currentClass?.name !== owner) {
775
- this.diagnostics.error(`'${memberName}' is private and not accessible outside class '${owner}'`, line, col);
775
+ this.diagnostics.error("KS4028", `'${memberName}' is private and not accessible outside class '${owner}'`, line, col);
776
776
  }
777
777
  return;
778
778
  }
779
779
  // protected
780
780
  if (!ctx.currentClass || !(ctx.currentClass.name === owner || this.isSubclass(ctx.currentClass.name, owner))) {
781
- this.diagnostics.error(`'${memberName}' is protected and only accessible within '${owner}' or its subclasses`, line, col);
781
+ this.diagnostics.error("KS4029", `'${memberName}' is protected and only accessible within '${owner}' or its subclasses`, line, col);
782
782
  }
783
783
  }
784
784
  // Assignability: is a value of type `from` usable where type `to` is expected?
@@ -840,13 +840,13 @@ export class Checker {
840
840
  resolveBodyReturnType(declaredReturnType, isAsync, line, col) {
841
841
  if (isAsync) {
842
842
  if (declaredReturnType.kind !== "task") {
843
- this.diagnostics.error(`'async' functions/methods must return 'task' or 'task<T>', got '${T.typeToString(declaredReturnType)}'`, line, col);
843
+ this.diagnostics.error("KS4030", `'async' functions/methods must return 'task' or 'task<T>', got '${T.typeToString(declaredReturnType)}'`, line, col);
844
844
  return T.UNKNOWN;
845
845
  }
846
846
  return declaredReturnType.resultType;
847
847
  }
848
848
  if (declaredReturnType.kind === "task") {
849
- this.diagnostics.error(`A function/method returning 'task'/'task<T>' must be marked 'async'`, line, col);
849
+ this.diagnostics.error("KS4031", `A function/method returning 'task'/'task<T>' must be marked 'async'`, line, col);
850
850
  }
851
851
  return declaredReturnType;
852
852
  }
@@ -886,13 +886,13 @@ export class Checker {
886
886
  const baseCtorParams = this.lookupCtorParams(info.superclass);
887
887
  const baseCtx = { returnType: T.VOID, currentClass: info, inConstructor: false, loopDepth: 0, isAsync: false };
888
888
  if (decl.constructor.baseArgs.length !== baseCtorParams.length) {
889
- this.diagnostics.error(`Expected ${baseCtorParams.length} base constructor argument(s), got ${decl.constructor.baseArgs.length}`, decl.constructor.line, decl.constructor.col);
889
+ this.diagnostics.error("KS4032", `Expected ${baseCtorParams.length} base constructor argument(s), got ${decl.constructor.baseArgs.length}`, decl.constructor.line, decl.constructor.col);
890
890
  }
891
891
  decl.constructor.baseArgs.forEach((arg, i) => {
892
892
  const expected = baseCtorParams[i] ?? T.UNKNOWN;
893
893
  const argType = this.checkExpressionExpecting(arg, expected, paramScope, baseCtx);
894
894
  if (!this.isAssignableType(argType, expected)) {
895
- this.diagnostics.error(`Base constructor argument ${i + 1} has type '${T.typeToString(argType)}', expected '${T.typeToString(expected)}'`, arg.line, arg.col);
895
+ this.diagnostics.error("KS4033", `Base constructor argument ${i + 1} has type '${T.typeToString(argType)}', expected '${T.typeToString(expected)}'`, arg.line, arg.col);
896
896
  }
897
897
  });
898
898
  }
@@ -922,7 +922,7 @@ export class Checker {
922
922
  isAsync: false,
923
923
  });
924
924
  if (!this.isAssignableType(initType, declaredType)) {
925
- this.diagnostics.error(`Cannot assign value of type '${T.typeToString(initType)}' to static field of type '${T.typeToString(declaredType)}'`, field.line, field.col);
925
+ this.diagnostics.error("KS4034", `Cannot assign value of type '${T.typeToString(initType)}' to static field of type '${T.typeToString(declaredType)}'`, field.line, field.col);
926
926
  }
927
927
  }
928
928
  }
@@ -939,7 +939,7 @@ export class Checker {
939
939
  this.recordHover(stmt.nameLine, stmt.nameCol, `${stmt.isConst ? "const" : "let"} ${stmt.name}: ${T.typeToString(declaredType)}`);
940
940
  const initType = this.checkExpressionExpecting(stmt.init, declaredType, scope, ctx);
941
941
  if (!this.isAssignableType(initType, declaredType)) {
942
- this.diagnostics.error(`Cannot assign value of type '${T.typeToString(initType)}' to variable of type '${T.typeToString(declaredType)}'`, stmt.line, stmt.col);
942
+ this.diagnostics.error("KS4035", `Cannot assign value of type '${T.typeToString(initType)}' to variable of type '${T.typeToString(declaredType)}'`, stmt.line, stmt.col);
943
943
  }
944
944
  scope.declare(stmt.name, declaredType, stmt.isConst);
945
945
  return;
@@ -994,11 +994,11 @@ export class Checker {
994
994
  const declaredVarType = this.resolveType(stmt.varType, stmt.line, stmt.col);
995
995
  if (iterableType.kind === "array") {
996
996
  if (!this.isAssignableType(iterableType.element, declaredVarType)) {
997
- this.diagnostics.error(`Cannot use loop variable of type '${T.typeToString(declaredVarType)}' for array of '${T.typeToString(iterableType.element)}'`, stmt.line, stmt.col);
997
+ this.diagnostics.error("KS4036", `Cannot use loop variable of type '${T.typeToString(declaredVarType)}' for array of '${T.typeToString(iterableType.element)}'`, stmt.line, stmt.col);
998
998
  }
999
999
  }
1000
1000
  else if (iterableType.kind !== "unknown") {
1001
- this.diagnostics.error(`Cannot iterate over non-array type '${T.typeToString(iterableType)}'`, stmt.line, stmt.col);
1001
+ this.diagnostics.error("KS4037", `Cannot iterate over non-array type '${T.typeToString(iterableType)}'`, stmt.line, stmt.col);
1002
1002
  }
1003
1003
  const forScope = scope.child();
1004
1004
  forScope.declare(stmt.varName, declaredVarType, false);
@@ -1008,14 +1008,14 @@ export class Checker {
1008
1008
  case "ReturnStatement": {
1009
1009
  const actual = stmt.value ? this.checkExpressionExpecting(stmt.value, ctx.returnType, scope, ctx) : T.VOID;
1010
1010
  if (!this.isAssignableType(actual, ctx.returnType)) {
1011
- this.diagnostics.error(`Return type '${T.typeToString(actual)}' does not match declared return type '${T.typeToString(ctx.returnType)}'`, stmt.line, stmt.col);
1011
+ this.diagnostics.error("KS4038", `Return type '${T.typeToString(actual)}' does not match declared return type '${T.typeToString(ctx.returnType)}'`, stmt.line, stmt.col);
1012
1012
  }
1013
1013
  return;
1014
1014
  }
1015
1015
  case "BreakStatement":
1016
1016
  case "ContinueStatement":
1017
1017
  if (ctx.loopDepth === 0) {
1018
- this.diagnostics.error(`'${stmt.kind === "BreakStatement" ? "break" : "continue"}' used outside of a loop`, stmt.line, stmt.col);
1018
+ this.diagnostics.error("KS4039", `'${stmt.kind === "BreakStatement" ? "break" : "continue"}' used outside of a loop`, stmt.line, stmt.col);
1019
1019
  }
1020
1020
  return;
1021
1021
  case "ExpressionStatement":
@@ -1039,30 +1039,30 @@ export class Checker {
1039
1039
  this.checkExpression(stmt.expression, scope, ctx);
1040
1040
  return;
1041
1041
  case "FunctionDecl":
1042
- this.diagnostics.error(`Nested function declarations are not supported`, stmt.line, stmt.col);
1042
+ this.diagnostics.error("KS4040", `Nested function declarations are not supported`, stmt.line, stmt.col);
1043
1043
  return;
1044
1044
  case "ClassDecl":
1045
- this.diagnostics.error(`Nested class declarations are not supported`, stmt.line, stmt.col);
1045
+ this.diagnostics.error("KS4041", `Nested class declarations are not supported`, stmt.line, stmt.col);
1046
1046
  return;
1047
1047
  case "InterfaceDecl":
1048
- this.diagnostics.error(`Nested interface declarations are not supported`, stmt.line, stmt.col);
1048
+ this.diagnostics.error("KS4042", `Nested interface declarations are not supported`, stmt.line, stmt.col);
1049
1049
  return;
1050
1050
  case "EnumDecl":
1051
- this.diagnostics.error(`Nested enum declarations are not supported`, stmt.line, stmt.col);
1051
+ this.diagnostics.error("KS4043", `Nested enum declarations are not supported`, stmt.line, stmt.col);
1052
1052
  return;
1053
1053
  case "ExternFunctionDecl":
1054
1054
  case "ExternClassDecl":
1055
1055
  case "ExternValueDecl":
1056
- this.diagnostics.error(`'extern' declarations are only allowed at the top level of a file`, stmt.line, stmt.col);
1056
+ this.diagnostics.error("KS4044", `'extern' declarations are only allowed at the top level of a file`, stmt.line, stmt.col);
1057
1057
  return;
1058
1058
  case "RawStringDecl":
1059
- this.diagnostics.error(`'raw' declarations are only allowed at the top level of a file`, stmt.line, stmt.col);
1059
+ this.diagnostics.error("KS4045", `'raw' declarations are only allowed at the top level of a file`, stmt.line, stmt.col);
1060
1060
  return;
1061
1061
  }
1062
1062
  }
1063
1063
  expectType(actual, expected, line, col, context) {
1064
1064
  if (!T.typesEqual(actual, expected)) {
1065
- this.diagnostics.error(`Expected type '${T.typeToString(expected)}' for ${context}, got '${T.typeToString(actual)}'`, line, col);
1065
+ this.diagnostics.error("KS4046", `Expected type '${T.typeToString(expected)}' for ${context}, got '${T.typeToString(actual)}'`, line, col);
1066
1066
  }
1067
1067
  }
1068
1068
  // Recognizes `name != null` / `name == null` (either operand order) as a
@@ -1129,7 +1129,7 @@ export class Checker {
1129
1129
  const first = elementTypes[0];
1130
1130
  for (let i = 1; i < elementTypes.length; i++) {
1131
1131
  if (!T.typesEqual(elementTypes[i], first)) {
1132
- this.diagnostics.error(`Array elements must all have the same type`, expr.line, expr.col);
1132
+ this.diagnostics.error("KS4047", `Array elements must all have the same type`, expr.line, expr.col);
1133
1133
  break;
1134
1134
  }
1135
1135
  }
@@ -1156,14 +1156,14 @@ export class Checker {
1156
1156
  const fnInfo = this.functions.get(expr.name);
1157
1157
  if (fnInfo)
1158
1158
  return T.functionType(fnInfo.params, fnInfo.returnType);
1159
- this.diagnostics.error(`Undefined identifier '${expr.name}'`, expr.line, expr.col);
1159
+ this.diagnostics.error("KS4048", `Undefined identifier '${expr.name}'`, expr.line, expr.col);
1160
1160
  return T.UNKNOWN;
1161
1161
  }
1162
1162
  case "ThisExpr": {
1163
1163
  const found = scope.resolve("this");
1164
1164
  if (found)
1165
1165
  return found.type;
1166
- this.diagnostics.error(`'this' used outside of a class method`, expr.line, expr.col);
1166
+ this.diagnostics.error("KS4049", `'this' used outside of a class method`, expr.line, expr.col);
1167
1167
  return T.UNKNOWN;
1168
1168
  }
1169
1169
  case "UnaryExpr": {
@@ -1203,13 +1203,13 @@ export class Checker {
1203
1203
  if (expr.target.kind === "Identifier") {
1204
1204
  const found = scope.resolve(expr.target.name);
1205
1205
  if (found?.isConst) {
1206
- this.diagnostics.error(`Cannot assign to const variable '${expr.target.name}'`, expr.line, expr.col);
1206
+ this.diagnostics.error("KS4050", `Cannot assign to const variable '${expr.target.name}'`, expr.line, expr.col);
1207
1207
  }
1208
1208
  }
1209
1209
  }
1210
1210
  const valueType = this.checkExpressionExpecting(expr.value, targetType, scope, ctx);
1211
1211
  if (!this.isAssignableType(valueType, targetType)) {
1212
- this.diagnostics.error(`Cannot assign value of type '${T.typeToString(valueType)}' to target of type '${T.typeToString(targetType)}'`, expr.line, expr.col);
1212
+ this.diagnostics.error("KS4051", `Cannot assign value of type '${T.typeToString(valueType)}' to target of type '${T.typeToString(targetType)}'`, expr.line, expr.col);
1213
1213
  }
1214
1214
  return targetType;
1215
1215
  }
@@ -1226,7 +1226,7 @@ export class Checker {
1226
1226
  if (objType.kind === "array")
1227
1227
  return objType.element;
1228
1228
  if (objType.kind !== "unknown") {
1229
- this.diagnostics.error(`Cannot index into non-array type '${T.typeToString(objType)}'`, expr.line, expr.col);
1229
+ this.diagnostics.error("KS4052", `Cannot index into non-array type '${T.typeToString(objType)}'`, expr.line, expr.col);
1230
1230
  }
1231
1231
  return T.UNKNOWN;
1232
1232
  }
@@ -1240,13 +1240,13 @@ export class Checker {
1240
1240
  return this.checkLambda(expr, T.UNKNOWN, scope, ctx);
1241
1241
  case "AwaitExpr": {
1242
1242
  if (!ctx.isAsync) {
1243
- this.diagnostics.error(`'await' can only be used inside an 'async' function or method`, expr.line, expr.col);
1243
+ this.diagnostics.error("KS4053", `'await' can only be used inside an 'async' function or method`, expr.line, expr.col);
1244
1244
  }
1245
1245
  const operandType = this.checkExpression(expr.operand, scope, ctx);
1246
1246
  if (operandType.kind === "task")
1247
1247
  return operandType.resultType;
1248
1248
  if (operandType.kind !== "unknown") {
1249
- this.diagnostics.error(`Cannot 'await' a value of type '${T.typeToString(operandType)}'`, expr.line, expr.col);
1249
+ this.diagnostics.error("KS4054", `Cannot 'await' a value of type '${T.typeToString(operandType)}'`, expr.line, expr.col);
1250
1250
  }
1251
1251
  return T.UNKNOWN;
1252
1252
  }
@@ -1268,7 +1268,7 @@ export class Checker {
1268
1268
  return this.checkLambda(expr, expected, scope, ctx);
1269
1269
  if (expr.kind === "NullLiteral") {
1270
1270
  if (expected.kind !== "nullable" && expected.kind !== "unknown") {
1271
- this.diagnostics.error(`Cannot assign 'null' to non-nullable type '${T.typeToString(expected)}'`, expr.line, expr.col);
1271
+ this.diagnostics.error("KS4055", `Cannot assign 'null' to non-nullable type '${T.typeToString(expected)}'`, expr.line, expr.col);
1272
1272
  return T.UNKNOWN;
1273
1273
  }
1274
1274
  return expected;
@@ -1278,7 +1278,7 @@ export class Checker {
1278
1278
  checkLambda(expr, expected, scope, ctx) {
1279
1279
  if (expected.kind !== "function") {
1280
1280
  if (expected.kind !== "unknown") {
1281
- this.diagnostics.error(`Lambda expression is not valid where type '${T.typeToString(expected)}' is expected`, expr.line, expr.col);
1281
+ this.diagnostics.error("KS4056", `Lambda expression is not valid where type '${T.typeToString(expected)}' is expected`, expr.line, expr.col);
1282
1282
  }
1283
1283
  const paramTypes = expr.params.map((p) => this.resolveType(p.type, expr.line, expr.col));
1284
1284
  const lambdaScope = scope.child();
@@ -1289,13 +1289,13 @@ export class Checker {
1289
1289
  return T.functionType(paramTypes, actualReturnType);
1290
1290
  }
1291
1291
  if (expr.params.length !== expected.params.length) {
1292
- this.diagnostics.error(`Lambda has ${expr.params.length} parameter(s), but ${expected.params.length} were expected`, expr.line, expr.col);
1292
+ this.diagnostics.error("KS4057", `Lambda has ${expr.params.length} parameter(s), but ${expected.params.length} were expected`, expr.line, expr.col);
1293
1293
  }
1294
1294
  const paramTypes = expr.params.map((p, i) => {
1295
1295
  const declared = this.resolveType(p.type, expr.line, expr.col);
1296
1296
  const expectedParamType = expected.params[i];
1297
1297
  if (expectedParamType && !T.typesEqual(declared, expectedParamType)) {
1298
- this.diagnostics.error(`Lambda parameter '${p.name}' has type '${T.typeToString(declared)}', expected '${T.typeToString(expectedParamType)}'`, expr.line, expr.col);
1298
+ this.diagnostics.error("KS4058", `Lambda parameter '${p.name}' has type '${T.typeToString(declared)}', expected '${T.typeToString(expectedParamType)}'`, expr.line, expr.col);
1299
1299
  }
1300
1300
  return declared;
1301
1301
  });
@@ -1330,7 +1330,7 @@ export class Checker {
1330
1330
  }
1331
1331
  const actual = this.checkExpressionExpecting(expr.body, expectedReturnType, scope, lambdaCtx);
1332
1332
  if (expectedReturnType.kind !== "unknown" && !this.isAssignableType(actual, expectedReturnType)) {
1333
- this.diagnostics.error(`Lambda body has type '${T.typeToString(actual)}', expected '${T.typeToString(expectedReturnType)}'`, expr.line, expr.col);
1333
+ this.diagnostics.error("KS4059", `Lambda body has type '${T.typeToString(actual)}', expected '${T.typeToString(expectedReturnType)}'`, expr.line, expr.col);
1334
1334
  }
1335
1335
  return actual;
1336
1336
  }
@@ -1361,12 +1361,12 @@ export class Checker {
1361
1361
  if (nullSide) {
1362
1362
  const otherType = nullSide === "left" ? rightType : leftType;
1363
1363
  if (otherType.kind !== "nullable" && otherType.kind !== "unknown") {
1364
- this.diagnostics.error(`Type '${T.typeToString(otherType)}' can never be null — only a nullable type (e.g. '${T.typeToString(otherType)}?') can be compared to 'null'`, line, col);
1364
+ this.diagnostics.error("KS4060", `Type '${T.typeToString(otherType)}' can never be null — only a nullable type (e.g. '${T.typeToString(otherType)}?') can be compared to 'null'`, line, col);
1365
1365
  }
1366
1366
  return T.BOOL;
1367
1367
  }
1368
1368
  if (!T.typesEqual(leftType, rightType)) {
1369
- this.diagnostics.error(`Cannot compare '${T.typeToString(leftType)}' with '${T.typeToString(rightType)}'`, line, col);
1369
+ this.diagnostics.error("KS4061", `Cannot compare '${T.typeToString(leftType)}' with '${T.typeToString(rightType)}'`, line, col);
1370
1370
  }
1371
1371
  return T.BOOL;
1372
1372
  }
@@ -1387,7 +1387,7 @@ export class Checker {
1387
1387
  expr.args.forEach((a) => this.checkExpression(a, scope, ctx));
1388
1388
  return T.VOID;
1389
1389
  }
1390
- this.diagnostics.error(`Undefined function '${expr.callee.name}'`, expr.line, expr.col);
1390
+ this.diagnostics.error("KS4062", `Undefined function '${expr.callee.name}'`, expr.line, expr.col);
1391
1391
  expr.args.forEach((a) => this.checkExpression(a, scope, ctx));
1392
1392
  return T.UNKNOWN;
1393
1393
  }
@@ -1427,43 +1427,43 @@ export class Checker {
1427
1427
  return calleeType.returnType;
1428
1428
  }
1429
1429
  if (calleeType.kind !== "unknown") {
1430
- this.diagnostics.error(`Cannot call a value of type '${T.typeToString(calleeType)}'`, expr.line, expr.col);
1430
+ this.diagnostics.error("KS4063", `Cannot call a value of type '${T.typeToString(calleeType)}'`, expr.line, expr.col);
1431
1431
  }
1432
1432
  expr.args.forEach((a) => this.checkExpression(a, scope, ctx));
1433
1433
  return T.UNKNOWN;
1434
1434
  }
1435
1435
  checkArgs(expr, paramTypes, scope, ctx) {
1436
1436
  if (expr.args.length !== paramTypes.length) {
1437
- this.diagnostics.error(`Expected ${paramTypes.length} argument(s), got ${expr.args.length}`, expr.line, expr.col);
1437
+ this.diagnostics.error("KS4064", `Expected ${paramTypes.length} argument(s), got ${expr.args.length}`, expr.line, expr.col);
1438
1438
  }
1439
1439
  expr.args.forEach((arg, i) => {
1440
1440
  const expected = paramTypes[i] ?? T.UNKNOWN;
1441
1441
  const argType = this.checkExpressionExpecting(arg, expected, scope, ctx);
1442
1442
  if (!this.isAssignableType(argType, expected)) {
1443
- this.diagnostics.error(`Argument ${i + 1} has type '${T.typeToString(argType)}', expected '${T.typeToString(expected)}'`, arg.line, arg.col);
1443
+ this.diagnostics.error("KS4065", `Argument ${i + 1} has type '${T.typeToString(argType)}', expected '${T.typeToString(expected)}'`, arg.line, arg.col);
1444
1444
  }
1445
1445
  });
1446
1446
  }
1447
1447
  checkNew(expr, scope, ctx) {
1448
1448
  if (this.interfaces.has(expr.className)) {
1449
- this.diagnostics.error(`Cannot instantiate interface '${expr.className}'`, expr.line, expr.col);
1449
+ this.diagnostics.error("KS4066", `Cannot instantiate interface '${expr.className}'`, expr.line, expr.col);
1450
1450
  expr.args.forEach((a) => this.checkExpression(a, scope, ctx));
1451
1451
  return T.UNKNOWN;
1452
1452
  }
1453
1453
  if (this.enums.has(expr.className)) {
1454
- this.diagnostics.error(`Cannot instantiate enum '${expr.className}'`, expr.line, expr.col);
1454
+ this.diagnostics.error("KS4067", `Cannot instantiate enum '${expr.className}'`, expr.line, expr.col);
1455
1455
  expr.args.forEach((a) => this.checkExpression(a, scope, ctx));
1456
1456
  return T.UNKNOWN;
1457
1457
  }
1458
1458
  const info = this.classes.get(expr.className);
1459
1459
  if (!info) {
1460
- this.diagnostics.error(`Unknown class '${expr.className}'`, expr.line, expr.col);
1460
+ this.diagnostics.error("KS4068", `Unknown class '${expr.className}'`, expr.line, expr.col);
1461
1461
  expr.args.forEach((a) => this.checkExpression(a, scope, ctx));
1462
1462
  return T.UNKNOWN;
1463
1463
  }
1464
1464
  let typeArg;
1465
1465
  if (info.typeParam && !expr.typeArgs) {
1466
- this.diagnostics.error(`Generic class '${expr.className}' requires a type argument (e.g. 'new ${expr.className}<T>(...)')`, expr.line, expr.col);
1466
+ this.diagnostics.error("KS4069", `Generic class '${expr.className}' requires a type argument (e.g. 'new ${expr.className}<T>(...)')`, expr.line, expr.col);
1467
1467
  // Abstractly-typed (T-containing) ctor params, un-substitutable
1468
1468
  // without a real type argument, would otherwise cascade into a
1469
1469
  // confusing "expected 'T'" error on every argument — one clear error
@@ -1472,7 +1472,7 @@ export class Checker {
1472
1472
  return T.UNKNOWN;
1473
1473
  }
1474
1474
  if (!info.typeParam && expr.typeArgs) {
1475
- this.diagnostics.error(`Class '${expr.className}' is not generic — it doesn't take a type argument`, expr.line, expr.col);
1475
+ this.diagnostics.error("KS4070", `Class '${expr.className}' is not generic — it doesn't take a type argument`, expr.line, expr.col);
1476
1476
  expr.args.forEach((a) => this.checkExpression(a, scope, ctx));
1477
1477
  return T.UNKNOWN;
1478
1478
  }
@@ -1487,13 +1487,13 @@ export class Checker {
1487
1487
  ctorParams = ctorParams.map((p) => this.substituteTypeParam(p, paramName, arg));
1488
1488
  }
1489
1489
  if (expr.args.length !== ctorParams.length) {
1490
- this.diagnostics.error(`Expected ${ctorParams.length} constructor argument(s), got ${expr.args.length}`, expr.line, expr.col);
1490
+ this.diagnostics.error("KS4071", `Expected ${ctorParams.length} constructor argument(s), got ${expr.args.length}`, expr.line, expr.col);
1491
1491
  }
1492
1492
  expr.args.forEach((arg, i) => {
1493
1493
  const expected = ctorParams[i] ?? T.UNKNOWN;
1494
1494
  const argType = this.checkExpressionExpecting(arg, expected, scope, ctx);
1495
1495
  if (!this.isAssignableType(argType, expected)) {
1496
- this.diagnostics.error(`Constructor argument ${i + 1} has type '${T.typeToString(argType)}', expected '${T.typeToString(expected)}'`, arg.line, arg.col);
1496
+ this.diagnostics.error("KS4072", `Constructor argument ${i + 1} has type '${T.typeToString(argType)}', expected '${T.typeToString(expected)}'`, arg.line, arg.col);
1497
1497
  }
1498
1498
  });
1499
1499
  return T.classType(expr.className, typeArg);
@@ -1538,7 +1538,7 @@ export class Checker {
1538
1538
  // inference is needed there at all.
1539
1539
  checkArrayMap(expr, elementType, scope, ctx) {
1540
1540
  if (expr.args.length !== 1) {
1541
- this.diagnostics.error(`Map expects exactly 1 argument, got ${expr.args.length}`, expr.line, expr.col);
1541
+ this.diagnostics.error("KS4073", `Map expects exactly 1 argument, got ${expr.args.length}`, expr.line, expr.col);
1542
1542
  expr.args.forEach((a) => this.checkExpression(a, scope, ctx));
1543
1543
  return T.arrayOf(T.UNKNOWN);
1544
1544
  }
@@ -1547,12 +1547,12 @@ export class Checker {
1547
1547
  const argType = this.checkExpressionExpecting(arg, expectedCallbackType, scope, ctx);
1548
1548
  if (argType.kind !== "function") {
1549
1549
  if (argType.kind !== "unknown") {
1550
- this.diagnostics.error(`Map expects a function as its argument, got '${T.typeToString(argType)}'`, arg.line, arg.col);
1550
+ this.diagnostics.error("KS4074", `Map expects a function as its argument, got '${T.typeToString(argType)}'`, arg.line, arg.col);
1551
1551
  }
1552
1552
  return T.arrayOf(T.UNKNOWN);
1553
1553
  }
1554
1554
  if (argType.params.length !== 1 || !this.isAssignableType(elementType, argType.params[0])) {
1555
- this.diagnostics.error(`Map callback must take a single '${T.typeToString(elementType)}' parameter, got '${T.typeToString(argType)}'`, arg.line, arg.col);
1555
+ this.diagnostics.error("KS4075", `Map callback must take a single '${T.typeToString(elementType)}' parameter, got '${T.typeToString(argType)}'`, arg.line, arg.col);
1556
1556
  }
1557
1557
  return T.arrayOf(argType.returnType);
1558
1558
  }
@@ -1573,7 +1573,7 @@ export class Checker {
1573
1573
  this.recordHover(expr.object.line, expr.object.col, `enum ${objName}`);
1574
1574
  const enumInfo = this.enums.get(objName);
1575
1575
  if (!enumInfo.members.has(expr.property)) {
1576
- this.diagnostics.error(`Enum '${objName}' has no member '${expr.property}'`, expr.line, expr.col);
1576
+ this.diagnostics.error("KS4076", `Enum '${objName}' has no member '${expr.property}'`, expr.line, expr.col);
1577
1577
  return { type: T.UNKNOWN, methodInfo: null };
1578
1578
  }
1579
1579
  return { type: T.enumType(objName), methodInfo: null };
@@ -1590,13 +1590,13 @@ export class Checker {
1590
1590
  this.checkAccessibility(method.info.visibility, method.owner, ctx, expr.property, expr.line, expr.col);
1591
1591
  return { type: method.info.returnType, methodInfo: method.info };
1592
1592
  }
1593
- this.diagnostics.error(`Class '${objName}' has no static member '${expr.property}'`, expr.line, expr.col);
1593
+ this.diagnostics.error("KS4077", `Class '${objName}' has no static member '${expr.property}'`, expr.line, expr.col);
1594
1594
  return { type: T.UNKNOWN, methodInfo: null };
1595
1595
  }
1596
1596
  }
1597
1597
  const objectType = this.checkExpression(expr.object, scope, ctx);
1598
1598
  if (objectType.kind === "nullable") {
1599
- this.diagnostics.error(`Cannot access member '${expr.property}' on possibly-null type '${T.typeToString(objectType)}' — check for null first (e.g. 'if (x != null) { ... }')`, expr.line, expr.col);
1599
+ this.diagnostics.error("KS4078", `Cannot access member '${expr.property}' on possibly-null type '${T.typeToString(objectType)}' — check for null first (e.g. 'if (x != null) { ... }')`, expr.line, expr.col);
1600
1600
  return { type: T.UNKNOWN, methodInfo: null };
1601
1601
  }
1602
1602
  if (objectType.kind === "string") {
@@ -1610,7 +1610,7 @@ export class Checker {
1610
1610
  const method = STRING_METHODS[expr.property];
1611
1611
  if (method)
1612
1612
  return { type: method.returnType, methodInfo: method };
1613
- this.diagnostics.error(`Unknown string member '${expr.property}'`, expr.line, expr.col);
1613
+ this.diagnostics.error("KS4079", `Unknown string member '${expr.property}'`, expr.line, expr.col);
1614
1614
  return { type: T.UNKNOWN, methodInfo: null };
1615
1615
  }
1616
1616
  if (objectType.kind === "array") {
@@ -1626,7 +1626,7 @@ export class Checker {
1626
1626
  // ever reaching checkMember, so `arr.Map(f)` works; `arr.Map` used as
1627
1627
  // a bare value (not called) falls through to this error, same as an
1628
1628
  // unknown member — a known v1 restriction.
1629
- this.diagnostics.error(`Unknown array member '${expr.property}'`, expr.line, expr.col);
1629
+ this.diagnostics.error("KS4080", `Unknown array member '${expr.property}'`, expr.line, expr.col);
1630
1630
  return { type: T.UNKNOWN, methodInfo: null };
1631
1631
  }
1632
1632
  if (objectType.kind === "state") {
@@ -1642,7 +1642,7 @@ export class Checker {
1642
1642
  };
1643
1643
  return { type: method.returnType, methodInfo: method };
1644
1644
  }
1645
- this.diagnostics.error(`Unknown state member '${expr.property}'`, expr.line, expr.col);
1645
+ this.diagnostics.error("KS4081", `Unknown state member '${expr.property}'`, expr.line, expr.col);
1646
1646
  return { type: T.UNKNOWN, methodInfo: null };
1647
1647
  }
1648
1648
  if (objectType.kind === "class") {
@@ -1658,7 +1658,7 @@ export class Checker {
1658
1658
  if (isAssignTarget && !field.info.hasSetter) {
1659
1659
  const inOwnCtor = ctx.inConstructor && ctx.currentClass?.name === field.owner;
1660
1660
  if (!inOwnCtor) {
1661
- this.diagnostics.error(`'${expr.property}' has no setter and can only be assigned within ${field.owner}'s constructor`, expr.line, expr.col);
1661
+ this.diagnostics.error("KS4082", `'${expr.property}' has no setter and can only be assigned within ${field.owner}'s constructor`, expr.line, expr.col);
1662
1662
  }
1663
1663
  }
1664
1664
  return { type: substitute(field.info.type), methodInfo: null };
@@ -1669,7 +1669,7 @@ export class Checker {
1669
1669
  const info = paramName ? { ...method.info, params: method.info.params.map(substitute), returnType: substitute(method.info.returnType) } : method.info;
1670
1670
  return { type: info.returnType, methodInfo: info };
1671
1671
  }
1672
- this.diagnostics.error(`Class '${objectType.name}' has no member '${expr.property}'`, expr.line, expr.col);
1672
+ this.diagnostics.error("KS4083", `Class '${objectType.name}' has no member '${expr.property}'`, expr.line, expr.col);
1673
1673
  return { type: T.UNKNOWN, methodInfo: null };
1674
1674
  }
1675
1675
  if (objectType.kind === "interface") {
@@ -1684,11 +1684,11 @@ export class Checker {
1684
1684
  const returnType = substitute(sig.returnType);
1685
1685
  return { type: returnType, methodInfo: { params, returnType, visibility: "public", isVirtual: false, isOverride: false } };
1686
1686
  }
1687
- this.diagnostics.error(`Interface '${objectType.name}' has no member '${expr.property}'`, expr.line, expr.col);
1687
+ this.diagnostics.error("KS4084", `Interface '${objectType.name}' has no member '${expr.property}'`, expr.line, expr.col);
1688
1688
  return { type: T.UNKNOWN, methodInfo: null };
1689
1689
  }
1690
1690
  if (objectType.kind !== "unknown") {
1691
- this.diagnostics.error(`Cannot access member '${expr.property}' on type '${T.typeToString(objectType)}'`, expr.line, expr.col);
1691
+ this.diagnostics.error("KS4085", `Cannot access member '${expr.property}' on type '${T.typeToString(objectType)}'`, expr.line, expr.col);
1692
1692
  }
1693
1693
  return { type: T.UNKNOWN, methodInfo: null };
1694
1694
  }
@@ -1696,19 +1696,19 @@ export class Checker {
1696
1696
  const subjectType = this.checkExpression(expr.subject, scope, ctx);
1697
1697
  this.expectType(subjectType, T.STRING, expr.line, expr.col, "match subject");
1698
1698
  if (expr.arms.length === 0) {
1699
- this.diagnostics.error(`match expression must have at least one arm`, expr.line, expr.col);
1699
+ this.diagnostics.error("KS4086", `match expression must have at least one arm`, expr.line, expr.col);
1700
1700
  return T.UNKNOWN;
1701
1701
  }
1702
1702
  const lastArm = expr.arms[expr.arms.length - 1];
1703
1703
  if (lastArm.pattern.kind !== "WildcardPattern") {
1704
- this.diagnostics.error(`match expression must end with a wildcard '_' arm`, lastArm.line, lastArm.col);
1704
+ this.diagnostics.error("KS4087", `match expression must end with a wildcard '_' arm`, lastArm.line, lastArm.col);
1705
1705
  }
1706
1706
  let resultType = null;
1707
1707
  for (const arm of expr.arms) {
1708
1708
  if (arm.pattern.kind === "LiteralPattern") {
1709
1709
  for (const value of arm.pattern.values) {
1710
1710
  if (value.kind !== "StringLiteral") {
1711
- this.diagnostics.error(`match patterns must be string literals`, value.line, value.col);
1711
+ this.diagnostics.error("KS4088", `match patterns must be string literals`, value.line, value.col);
1712
1712
  }
1713
1713
  else {
1714
1714
  this.checkExpression(value, scope, ctx);
@@ -1721,7 +1721,7 @@ export class Checker {
1721
1721
  resultType = armResultType;
1722
1722
  }
1723
1723
  else if (!this.isAssignableType(armResultType, resultType)) {
1724
- this.diagnostics.error(`match arm result type '${T.typeToString(armResultType)}' does not match preceding arms' type '${T.typeToString(resultType)}'`, arm.line, arm.col);
1724
+ this.diagnostics.error("KS4089", `match arm result type '${T.typeToString(armResultType)}' does not match preceding arms' type '${T.typeToString(resultType)}'`, arm.line, arm.col);
1725
1725
  }
1726
1726
  }
1727
1727
  return resultType ?? T.UNKNOWN;