@thigasdevelopment/luam 0.19.12 → 1.0.1

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/luam.mjs CHANGED
@@ -3161,6 +3161,7 @@ var DEFAULT_COMPILER_OPTIONS = {
3161
3161
  oop: false,
3162
3162
  noUnusedLocals: false,
3163
3163
  noUnusedParameters: false,
3164
+ noImplicitGlobals: false,
3164
3165
  warningsAsErrors: false
3165
3166
  };
3166
3167
  var DEFAULT_SOURCE_MAPPING = {
@@ -3608,6 +3609,8 @@ var LUA_KEYWORDS = /* @__PURE__ */ new Set([
3608
3609
  "while"
3609
3610
  ]);
3610
3611
  var LUAM_KEYWORDS = /* @__PURE__ */ new Set([
3612
+ "async",
3613
+ "await",
3611
3614
  "class",
3612
3615
  "constructor",
3613
3616
  "continue",
@@ -3838,7 +3841,21 @@ function parseTypeName(stream) {
3838
3841
  }
3839
3842
  return { kind: "type-name", name: token.value, typeArguments, position: token.position };
3840
3843
  }
3844
+ function parseOptionalParameterType(stream) {
3845
+ const name = stream.next().value;
3846
+ const marker = stream.next();
3847
+ stream.next();
3848
+ const annotation = parseTypeAnnotation(stream);
3849
+ if (annotation.kind === "type-optional") {
3850
+ stream.report("parse-redundant-optional", 'The marker on the name already allows "nil". Remove the "?" after the type.', annotation.position);
3851
+ }
3852
+ const element = annotation.kind === "type-optional" ? annotation.element : annotation;
3853
+ return { name, annotation: { kind: "type-optional", element, position: marker.position } };
3854
+ }
3841
3855
  function parseParameterType(stream) {
3856
+ if (stream.check("identifier") && stream.checkAhead(1, "operator", "?") && stream.checkAhead(2, "punctuation", ":")) {
3857
+ return parseOptionalParameterType(stream);
3858
+ }
3842
3859
  let name = null;
3843
3860
  if (stream.check("identifier") && stream.checkAhead(1, "punctuation", ":")) {
3844
3861
  name = stream.next().value;
@@ -3889,7 +3906,7 @@ function parseGroupedType(stream) {
3889
3906
  return { kind: "type-tuple", elements, position: position2 };
3890
3907
  }
3891
3908
  function parseObjectMember(stream) {
3892
- const token = stream.expectName();
3909
+ const token = stream.expectMemberKey();
3893
3910
  const annotation = parseNamedAnnotation(stream, "field");
3894
3911
  if (annotation === null) {
3895
3912
  throw stream.error(`Key "${token.value}" of an object type requires a type annotation.`, "parse-invalid-type");
@@ -4034,9 +4051,16 @@ var TokenStream = class {
4034
4051
  index = 0;
4035
4052
  erased = [];
4036
4053
  spans = /* @__PURE__ */ new Map();
4054
+ breaksIndexAtNewline = false;
4037
4055
  constructor(tokens) {
4038
4056
  this.tokens = tokens;
4039
4057
  }
4058
+ stopIndexAtNewline(active) {
4059
+ this.breaksIndexAtNewline = active;
4060
+ }
4061
+ indexContinues(bracket) {
4062
+ return !this.breaksIndexAtNewline || this.index === 0 || bracket.position.line === this.peek(-1).end.line;
4063
+ }
4040
4064
  peek(offset = 0) {
4041
4065
  const token = this.tokens[Math.min(this.index + offset, this.tokens.length - 1)];
4042
4066
  return token;
@@ -4127,6 +4151,33 @@ var TokenStream = class {
4127
4151
  const token = this.peek(offset);
4128
4152
  return token.kind === "identifier" || token.kind === "keyword" && isLuamKeyword(token.value);
4129
4153
  }
4154
+ checkMemberKey(offset = 0) {
4155
+ return this.checkName(offset) || this.peek(offset).kind === "punctuation" && this.peek(offset).value === "[";
4156
+ }
4157
+ expectMemberKey() {
4158
+ if (!this.check("punctuation", "[")) {
4159
+ return this.expectName();
4160
+ }
4161
+ const open = this.next();
4162
+ const literal2 = this.current();
4163
+ if (literal2.kind !== "string") {
4164
+ throw this.error(`Expected a quoted key but found "${this.describeCurrent()}".`, "parse-unexpected-token");
4165
+ }
4166
+ this.next();
4167
+ const close = this.expect("punctuation", "]");
4168
+ return { ...literal2, position: open.position, end: close.end };
4169
+ }
4170
+ reservedNameAt(subject, offset = 0) {
4171
+ const token = this.peek(offset);
4172
+ const next = this.peek(offset + 1);
4173
+ const continues = next.kind === "punctuation" && (next.value === "," || next.value === ")" || next.value === ":") || next.kind === "operator" && (next.value === "?" || next.value === "=");
4174
+ if (token.kind !== "keyword" || !continues) {
4175
+ return null;
4176
+ }
4177
+ const message = `"${token.value}" is a reserved word and cannot name a ${subject}. Rename it \u2014 a property of the same name is still legal, so "value.${token.value}" keeps working.`;
4178
+ this.report("parse-reserved-name", message, token.position);
4179
+ return this.next();
4180
+ }
4130
4181
  expectName() {
4131
4182
  if (this.checkName()) {
4132
4183
  return this.next();
@@ -4214,7 +4265,8 @@ function parseParameter(stream) {
4214
4265
  }
4215
4266
  return { name: name2, annotation, isVararg: true, position: token.position };
4216
4267
  }
4217
- const name = stream.expect("identifier").value;
4268
+ const reserved = stream.reservedNameAt("parameter");
4269
+ const name = reserved === null ? stream.expect("identifier").value : reserved.value;
4218
4270
  return { name, annotation: parseNamedAnnotation(stream, "parameter"), isVararg: false, position: token.position };
4219
4271
  }
4220
4272
  function parseParameters(stream) {
@@ -4229,7 +4281,20 @@ function parseParameters(stream) {
4229
4281
  stream.expect("punctuation", ")");
4230
4282
  return parameters;
4231
4283
  }
4232
- function parseFunctionExpression(stream) {
4284
+ var ASYNC_MODIFIER = "async";
4285
+ function isAsyncFunctionStart(stream, offset = 0) {
4286
+ return stream.checkAhead(offset, "keyword", ASYNC_MODIFIER) && stream.checkAhead(offset + 1, "keyword", "function");
4287
+ }
4288
+ function consumeAsyncModifier(stream) {
4289
+ if (!isAsyncFunctionStart(stream)) {
4290
+ return false;
4291
+ }
4292
+ const checkpoint = stream.checkpoint();
4293
+ stream.next();
4294
+ stream.eraseToCurrent(checkpoint);
4295
+ return true;
4296
+ }
4297
+ function parseFunctionExpression(stream, isAsync = false) {
4233
4298
  const position2 = stream.expect("keyword", "function").position;
4234
4299
  const typeParameters = parseTypeParameters(stream);
4235
4300
  const parameters = parseParameters(stream);
@@ -4238,6 +4303,7 @@ function parseFunctionExpression(stream) {
4238
4303
  stream.expect("keyword", "end");
4239
4304
  return {
4240
4305
  kind: "function-expression",
4306
+ isAsync,
4241
4307
  typeParameters: typeParameters.names,
4242
4308
  typeConstraints: typeParameters.constraints,
4243
4309
  parameters,
@@ -4259,7 +4325,7 @@ function parseFunctionName(stream) {
4259
4325
  const property = stream.expect("identifier").value;
4260
4326
  return { name: { kind: "member-expression", object: name, property, position: token.position }, isMethod: true };
4261
4327
  }
4262
- function parseFunctionDeclaration(stream, isLocal, isExported = false, isHttpExport = false) {
4328
+ function parseFunctionDeclaration(stream, isLocal, isExported = false, isHttpExport = false, isAsync = false) {
4263
4329
  const position2 = stream.expect("keyword", "function").position;
4264
4330
  const { name, isMethod } = parseFunctionName(stream);
4265
4331
  const typeParameters = parseTypeParameters(stream);
@@ -4270,6 +4336,7 @@ function parseFunctionDeclaration(stream, isLocal, isExported = false, isHttpExp
4270
4336
  return {
4271
4337
  kind: "function-declaration",
4272
4338
  name,
4339
+ isAsync,
4273
4340
  isLocal,
4274
4341
  isExported,
4275
4342
  isHttpExport,
@@ -4324,6 +4391,14 @@ function isRightAssociative(operator) {
4324
4391
 
4325
4392
  // ../compiler/src/parser/expression.ts
4326
4393
  var LITERAL_KEYWORDS = /* @__PURE__ */ new Set(["nil", "true", "false"]);
4394
+ var AWAIT_OPERATOR = "await";
4395
+ function isAwaitStart(stream) {
4396
+ return stream.check("keyword", AWAIT_OPERATOR);
4397
+ }
4398
+ function parseAwaitExpression(stream) {
4399
+ const position2 = stream.next().position;
4400
+ return { kind: "await-expression", operand: parseSuffixed(stream), position: position2 };
4401
+ }
4327
4402
  function parseKeywordLiteral(token) {
4328
4403
  if (token.value === "nil") {
4329
4404
  return { kind: "nil-literal", position: token.position };
@@ -4382,6 +4457,10 @@ function parsePrimary(stream) {
4382
4457
  stream.next();
4383
4458
  return { kind: "identifier", name: token.value, position: token.position };
4384
4459
  }
4460
+ if (isAsyncFunctionStart(stream)) {
4461
+ consumeAsyncModifier(stream);
4462
+ return parseFunctionExpression(stream, true);
4463
+ }
4385
4464
  if (token.kind === "identifier") {
4386
4465
  stream.next();
4387
4466
  return { kind: "identifier", name: token.value, position: token.position };
@@ -4406,6 +4485,12 @@ function parsePrimary(stream) {
4406
4485
  stream.expect("punctuation", ")");
4407
4486
  return { kind: "group-expression", expression, position: token.position };
4408
4487
  }
4488
+ if (token.kind === "keyword" && isLuamKeyword(token.value)) {
4489
+ const message = `"${token.value}" is a reserved word and cannot be read as a value. Rename the declaration \u2014 a property of the same name is still legal, so "value.${token.value}" keeps working.`;
4490
+ stream.report("parse-reserved-name", message, token.position);
4491
+ stream.next();
4492
+ return { kind: "identifier", name: token.value, position: token.position };
4493
+ }
4409
4494
  throw stream.error(`Unexpected "${stream.describeCurrent()}" in expression.`, "parse-unexpected-token");
4410
4495
  }
4411
4496
  function parseArguments(stream) {
@@ -4440,6 +4525,9 @@ function parseSuffixed(stream) {
4440
4525
  continue;
4441
4526
  }
4442
4527
  if (token.kind === "punctuation" && token.value === "[") {
4528
+ if (!stream.indexContinues(token)) {
4529
+ return expression;
4530
+ }
4443
4531
  stream.next();
4444
4532
  const index = parseExpression(stream);
4445
4533
  stream.expect("punctuation", "]");
@@ -4465,6 +4553,9 @@ function parseSuffixed(stream) {
4465
4553
  }
4466
4554
  }
4467
4555
  function parseUnary(stream) {
4556
+ if (isAwaitStart(stream)) {
4557
+ return parseAwaitExpression(stream);
4558
+ }
4468
4559
  const token = stream.current();
4469
4560
  const isUnary2 = (token.kind === "operator" || token.kind === "keyword") && UNARY_OPERATORS.has(token.value);
4470
4561
  if (!isUnary2) {
@@ -4622,7 +4713,11 @@ function isDeclarationStart(stream) {
4622
4713
  if (token.value === "class") {
4623
4714
  return isClassHeader(stream, offset);
4624
4715
  }
4625
- return token.value === "interface" ? stream.checkAhead(offset + 2, "punctuation", "{") || stream.checkAhead(offset + 2, "keyword", "extends") : stream.checkAhead(offset + 2, "punctuation", "{");
4716
+ if (token.value === "interface") {
4717
+ const after = skipTypeParameters(stream, offset + 2);
4718
+ return stream.checkAhead(after, "punctuation", "{") || stream.checkAhead(after, "keyword", "extends");
4719
+ }
4720
+ return stream.checkAhead(offset + 2, "punctuation", "{");
4626
4721
  }
4627
4722
  function skipDecoratorArguments(stream) {
4628
4723
  let depth = 0;
@@ -4652,12 +4747,14 @@ function parseDecorators(stream) {
4652
4747
  }
4653
4748
  return decorators;
4654
4749
  }
4655
- function parseClassMethod(stream, token, decorators, isStatic) {
4750
+ function parseClassMethod(stream, token, decorators, isStatic, isAsync) {
4656
4751
  stream.expect("operator", "=");
4657
- const expression = parseFunctionExpression(stream);
4752
+ const modified = consumeAsyncModifier(stream) || isAsync;
4753
+ const expression = parseFunctionExpression(stream, modified);
4658
4754
  return {
4659
4755
  kind: "class-method",
4660
4756
  name: token.value,
4757
+ isAsync: modified,
4661
4758
  isConstructor: token.value === "constructor",
4662
4759
  isSynthetic: false,
4663
4760
  isStatic,
@@ -4670,13 +4767,14 @@ function parseClassMethod(stream, token, decorators, isStatic) {
4670
4767
  position: token.position
4671
4768
  };
4672
4769
  }
4673
- function parseBraceClassMethod(stream, token, decorators, isStatic) {
4770
+ function parseBraceClassMethod(stream, token, decorators, isStatic, isAsync) {
4674
4771
  const parameters = parseParameters(stream);
4675
4772
  const returnAnnotation = parseOptionalAnnotation(stream);
4676
4773
  const body = parseBraceBlock(stream);
4677
4774
  return {
4678
4775
  kind: "class-method",
4679
4776
  name: token.value,
4777
+ isAsync,
4680
4778
  isConstructor: token.value === "constructor",
4681
4779
  isSynthetic: false,
4682
4780
  isStatic,
@@ -4692,6 +4790,14 @@ function parseBraceClassMethod(stream, token, decorators, isStatic) {
4692
4790
  function parseFieldAnnotation(stream) {
4693
4791
  return parseNamedAnnotation(stream, "field");
4694
4792
  }
4793
+ function parseFieldValue(stream) {
4794
+ stream.stopIndexAtNewline(true);
4795
+ try {
4796
+ return parseExpression(stream);
4797
+ } finally {
4798
+ stream.stopIndexAtNewline(false);
4799
+ }
4800
+ }
4695
4801
  function expectClassFieldBoundary(stream, token) {
4696
4802
  const current = stream.current();
4697
4803
  const delimiter = current.kind === "punctuation" && (current.value === "}" || current.value === ";" || current.value === ",");
@@ -4701,12 +4807,12 @@ function expectClassFieldBoundary(stream, token) {
4701
4807
  throw stream.error(`Expected a line break or separator after class member "${token.value}".`, "parse-unexpected-token");
4702
4808
  }
4703
4809
  var STATIC_MODIFIER = "static";
4704
- function parseStaticModifier(stream) {
4705
- if (!stream.check("identifier", STATIC_MODIFIER)) {
4810
+ function parseMemberModifier(stream, modifier, kind = "identifier") {
4811
+ if (!stream.check(kind, modifier)) {
4706
4812
  return false;
4707
4813
  }
4708
- const modifier = stream.current();
4709
- if (!stream.checkName(1) || stream.peek(1).position.line !== modifier.position.line) {
4814
+ const token = stream.current();
4815
+ if (!stream.checkName(1) || stream.peek(1).position.line !== token.position.line) {
4710
4816
  return false;
4711
4817
  }
4712
4818
  const checkpoint = stream.checkpoint();
@@ -4716,17 +4822,18 @@ function parseStaticModifier(stream) {
4716
4822
  }
4717
4823
  function parseClassMember(stream) {
4718
4824
  const decorators = parseDecorators(stream);
4719
- const isStatic = parseStaticModifier(stream);
4720
- const token = stream.expectName();
4825
+ const isStatic = parseMemberModifier(stream, STATIC_MODIFIER);
4826
+ const isAsync = parseMemberModifier(stream, ASYNC_MODIFIER, "keyword");
4827
+ const token = stream.expectMemberKey();
4721
4828
  if (stream.check("punctuation", "(")) {
4722
4829
  stream.report("parse-class-method-form", `Write class member "${token.value}" as "${token.value} = function (...) ... end".`, token.position);
4723
- return parseBraceClassMethod(stream, token, decorators, isStatic);
4830
+ return parseBraceClassMethod(stream, token, decorators, isStatic, isAsync);
4724
4831
  }
4725
- if (stream.check("operator", "=") && stream.checkAhead(1, "keyword", "function")) {
4726
- return parseClassMethod(stream, token, decorators, isStatic);
4832
+ if (stream.check("operator", "=") && (stream.checkAhead(1, "keyword", "function") || isAsyncFunctionStart(stream, 1))) {
4833
+ return parseClassMethod(stream, token, decorators, isStatic, isAsync);
4727
4834
  }
4728
4835
  const annotation = parseFieldAnnotation(stream);
4729
- const value = stream.match("operator", "=") ? parseExpression(stream) : null;
4836
+ const value = stream.match("operator", "=") ? parseFieldValue(stream) : null;
4730
4837
  expectClassFieldBoundary(stream, token);
4731
4838
  return { kind: "class-field", name: token.value, annotation, value, decorators, isStatic, position: token.position };
4732
4839
  }
@@ -4739,6 +4846,7 @@ function parseClassModifiers(stream, declaration) {
4739
4846
  }
4740
4847
  do {
4741
4848
  declaration.interfaces.push(stream.expect("identifier").value);
4849
+ declaration.interfaceArguments.push(parseTypeArguments(stream));
4742
4850
  } while (stream.match("punctuation", ","));
4743
4851
  }
4744
4852
  }
@@ -4754,6 +4862,7 @@ function parseClassDeclaration(stream, decorators) {
4754
4862
  superClass: null,
4755
4863
  superClassArguments: [],
4756
4864
  interfaces: [],
4865
+ interfaceArguments: [],
4757
4866
  members: [],
4758
4867
  decorators,
4759
4868
  position: position2
@@ -4780,7 +4889,7 @@ function parseClassDeclaration(stream, decorators) {
4780
4889
  return declaration;
4781
4890
  }
4782
4891
  function parseInterfaceMember(stream) {
4783
- const token = stream.expectName();
4892
+ const token = stream.expectMemberKey();
4784
4893
  if (stream.check("punctuation", "(")) {
4785
4894
  const parameters = parseParameters(stream);
4786
4895
  const returnAnnotation = parseOptionalAnnotation(stream);
@@ -4796,6 +4905,7 @@ function parseInterfaceDeclaration(stream) {
4796
4905
  const checkpoint = stream.checkpoint();
4797
4906
  const position2 = stream.next().position;
4798
4907
  const name = stream.expect("identifier").value;
4908
+ const typeParameters = parseTypeParameters(stream);
4799
4909
  const superInterfaces = [];
4800
4910
  const members = [];
4801
4911
  if (stream.match("keyword", "extends")) {
@@ -4818,7 +4928,15 @@ function parseInterfaceDeclaration(stream) {
4818
4928
  }
4819
4929
  }
4820
4930
  stream.expect("punctuation", "}");
4821
- const declaration = { kind: "interface-declaration", name, superInterfaces, members, position: position2 };
4931
+ const declaration = {
4932
+ kind: "interface-declaration",
4933
+ name,
4934
+ typeParameters: typeParameters.names,
4935
+ typeConstraints: typeParameters.constraints,
4936
+ superInterfaces,
4937
+ members,
4938
+ position: position2
4939
+ };
4822
4940
  stream.eraseFrom(checkpoint, "declaration");
4823
4941
  return declaration;
4824
4942
  }
@@ -4879,7 +4997,7 @@ function parseExpressionList(stream) {
4879
4997
  return values;
4880
4998
  }
4881
4999
  function parseDeclarator(stream) {
4882
- const token = stream.expect("identifier");
5000
+ const token = stream.reservedNameAt("local") ?? stream.expect("identifier");
4883
5001
  return { name: token.value, annotation: parseNamedAnnotation(stream, "local"), position: token.position };
4884
5002
  }
4885
5003
  function parseLocalStatement(stream, position2) {
@@ -4973,7 +5091,34 @@ function invalidStatement(stream, target, start) {
4973
5091
  const message = `${subject} is not a statement. Assign it with "=", pass it to a call, or remove the line.`;
4974
5092
  return stream.errorAt(message, "parse-invalid-statement", start.position, start.end);
4975
5093
  }
5094
+ function parseGlobalDeclaration(stream) {
5095
+ const marked = stream.checkAhead(1, "operator", "?") && stream.checkAhead(2, "punctuation", ":");
5096
+ if (!stream.check("identifier") || !marked && !stream.checkAhead(1, "punctuation", ":")) {
5097
+ return null;
5098
+ }
5099
+ const point = stream.speculate();
5100
+ try {
5101
+ const declaration = parseDeclarator(stream);
5102
+ if (declaration.annotation !== null && stream.match("operator", "=")) {
5103
+ return { kind: "global-statement", declaration, values: parseExpressionList(stream), position: declaration.position };
5104
+ }
5105
+ } catch (error) {
5106
+ if (!(error instanceof ParserError)) {
5107
+ throw error;
5108
+ }
5109
+ }
5110
+ stream.rewind(point);
5111
+ return null;
5112
+ }
4976
5113
  function parseExpressionStatement(stream) {
5114
+ if (isAwaitStart(stream)) {
5115
+ const expression = parseAwaitExpression(stream);
5116
+ return { kind: "call-statement", expression, position: expression.position };
5117
+ }
5118
+ const declaration = parseGlobalDeclaration(stream);
5119
+ if (declaration !== null) {
5120
+ return declaration;
5121
+ }
4977
5122
  const start = stream.current();
4978
5123
  const position2 = start.position;
4979
5124
  const targets = [parseSuffixed(stream)];
@@ -5001,7 +5146,12 @@ function parseKeywordStatement(stream, value) {
5001
5146
  if (stream.check("keyword", "function")) {
5002
5147
  return parseFunctionDeclaration(stream, true);
5003
5148
  }
5004
- return stream.check("keyword", "enum") ? parseEnumDeclaration(stream, true) : parseLocalStatement(stream, token.position);
5149
+ if (isAsyncFunctionStart(stream)) {
5150
+ consumeAsyncModifier(stream);
5151
+ return parseFunctionDeclaration(stream, true, false, false, true);
5152
+ }
5153
+ const isEnum = stream.check("keyword", "enum") && stream.checkAhead(1, "identifier");
5154
+ return isEnum ? parseEnumDeclaration(stream, true) : parseLocalStatement(stream, token.position);
5005
5155
  }
5006
5156
  if (value === "function") {
5007
5157
  return parseFunctionDeclaration(stream, false);
@@ -5042,6 +5192,10 @@ function parseStatement(stream) {
5042
5192
  return statement;
5043
5193
  }
5044
5194
  }
5195
+ if (isAsyncFunctionStart(stream)) {
5196
+ consumeAsyncModifier(stream);
5197
+ return parseFunctionDeclaration(stream, false, false, false, true);
5198
+ }
5045
5199
  if (isTypeAlias(stream)) {
5046
5200
  return parseTypeAlias(stream);
5047
5201
  }
@@ -5266,10 +5420,21 @@ function isEmptyLiteral(type) {
5266
5420
  return type.kind === "record" && type.isLiteral === true && type.members.size === 0;
5267
5421
  }
5268
5422
  function widenInferred(type) {
5423
+ if (type.kind === "array") {
5424
+ return createArray(widenInferred(type.element));
5425
+ }
5426
+ if (type.kind === "union") {
5427
+ return createUnion(type.options.map(widenInferred));
5428
+ }
5269
5429
  if (type.kind !== "record" || type.isLiteral !== true) {
5270
5430
  return widenLiteral(type);
5271
5431
  }
5272
- return type.members.size === 0 ? TABLE_TYPE : createRecord(type.name, type.members, type.origin);
5432
+ if (type.members.size === 0) {
5433
+ return TABLE_TYPE;
5434
+ }
5435
+ const widened = new Map([...type.members].map(([name, member]) => [name, widenInferred(member)]));
5436
+ const record2 = createObjectType(widened);
5437
+ return record2.kind === "record" ? { ...record2, isInferred: true } : record2;
5273
5438
  }
5274
5439
  function createFunction(parameters, returnType, minimumArguments2, isVariadic = false, parameterNames, variadicType) {
5275
5440
  return {
@@ -5428,7 +5593,7 @@ function isFunctionAssignable(source, target, options) {
5428
5593
  return target.returnType.kind === "void" || isAssignable(source.returnType, target.returnType, options);
5429
5594
  }
5430
5595
  function isMapAssignable(source, target, options) {
5431
- if (source.kind === "table") {
5596
+ if (source.kind === "table" || isEmptyLiteral(source)) {
5432
5597
  return true;
5433
5598
  }
5434
5599
  if (source.kind === "array") {
@@ -5677,9 +5842,16 @@ var RUNTIME_HELPERS = {
5677
5842
  },
5678
5843
  env: { name: "env", file: "env.lua", injection: "manual", features: [], environment: "server" },
5679
5844
  math: { name: "math", file: "math.lua", injection: "automatic", features: ["number-extension"] },
5845
+ promise: {
5846
+ name: "promise",
5847
+ file: "promise.lua",
5848
+ injection: "reference",
5849
+ features: ["async-function"],
5850
+ globals: ["Promise", "delay", "sleep"]
5851
+ },
5680
5852
  string: { name: "string", file: "string.lua", injection: "automatic", features: ["string-extension", "template-string"] },
5681
5853
  table: { name: "table", file: "table.lua", injection: "automatic", features: ["table-extension"] },
5682
- threads: { name: "threads", file: "threads.lua", injection: "reference", features: ["thread"], globals: ["sleep", "Threads"] },
5854
+ threads: { name: "threads", file: "threads.lua", injection: "reference", features: ["thread"], globals: ["Threads"], requires: ["promise"] },
5683
5855
  validate: { name: "validate", file: "validate.lua", injection: "automatic", features: ["boundary-validation"] }
5684
5856
  };
5685
5857
  var DEVELOPMENT_RUNTIME_HELPERS = {
@@ -5741,6 +5913,9 @@ var COMPILER_OPTION_FIELDS = [
5741
5913
  }),
5742
5914
  field("oop", BOOLEAN_TYPE, "Enables the MTA OOP API in the checker and the generated meta.xml.", { defaultValue: DEFAULT_COMPILER_OPTIONS.oop }),
5743
5915
  field("noUnusedLocals", BOOLEAN_TYPE, "Reports local declarations that are never read.", { defaultValue: DEFAULT_COMPILER_OPTIONS.noUnusedLocals }),
5916
+ field("noImplicitGlobals", BOOLEAN_TYPE, "Reports an assignment that creates a global the project never declares.", {
5917
+ defaultValue: DEFAULT_COMPILER_OPTIONS.noImplicitGlobals
5918
+ }),
5744
5919
  field("noUnusedParameters", BOOLEAN_TYPE, "Reports function and method parameters that are never read.", {
5745
5920
  defaultValue: DEFAULT_COMPILER_OPTIONS.noUnusedParameters
5746
5921
  }),
@@ -6802,6 +6977,7 @@ function readCompilerOptions(value) {
6802
6977
  strict: flag(source, "strict", DEFAULT_COMPILER_OPTIONS.strict),
6803
6978
  oop: flag(source, "oop", DEFAULT_COMPILER_OPTIONS.oop),
6804
6979
  noUnusedLocals: flag(source, "noUnusedLocals", DEFAULT_COMPILER_OPTIONS.noUnusedLocals),
6980
+ noImplicitGlobals: flag(source, "noImplicitGlobals", DEFAULT_COMPILER_OPTIONS.noImplicitGlobals),
6805
6981
  noUnusedParameters: flag(source, "noUnusedParameters", DEFAULT_COMPILER_OPTIONS.noUnusedParameters),
6806
6982
  warningsAsErrors: flag(source, "warningsAsErrors", DEFAULT_COMPILER_OPTIONS.warningsAsErrors)
6807
6983
  };
@@ -6978,7 +7154,7 @@ import { tmpdir } from "node:os";
6978
7154
  import { join as join2 } from "node:path";
6979
7155
 
6980
7156
  // src/cli/version.ts
6981
- var VERSION = true ? "0.19.12" : "0.0.0-dev";
7157
+ var VERSION = true ? "1.0.1" : "0.0.0-dev";
6982
7158
  var PROGRAM_NAME = "luam";
6983
7159
  var PROGRAM_DESCRIPTION = "luam \u2014 the Luam compiler for Multi Theft Auto resources.";
6984
7160
 
@@ -7042,7 +7218,7 @@ function runEditorCommand(command, args) {
7042
7218
  }
7043
7219
 
7044
7220
  // src/editor/editor-service.ts
7045
- var EXTENSION_ID = "thigasdevelopment.luam";
7221
+ var EXTENSION_ID = "luam.luam";
7046
7222
  var SUPPORTED_EDITORS = [
7047
7223
  { id: "vscode", name: "Visual Studio Code", command: "code" },
7048
7224
  { id: "vscode-insiders", name: "Visual Studio Code Insiders", command: "code-insiders" },
@@ -8862,12 +9038,13 @@ var TEST_DECLARATIONS = [
8862
9038
 
8863
9039
  // ../compiler/src/checker/ambient.ts
8864
9040
  var EVENT_NAME_PREFIX = "event:";
8865
- var EMPTY_AMBIENT = { classes: [], interfaces: [], enums: [], globals: [], events: [] };
9041
+ var EMPTY_AMBIENT = { classes: [], interfaces: [], enums: [], aliases: [], globals: [], events: [] };
8866
9042
  function ambientFromRegistry(registry) {
8867
9043
  return {
8868
9044
  classes: registry.allClasses(),
8869
- interfaces: registry.allInterfaces(),
9045
+ interfaces: registry.allInterfaces().filter((info) => info.isBuiltin !== true),
8870
9046
  enums: registry.allEnums().filter((info) => info.isLocal !== true),
9047
+ aliases: registry.allAliases(),
8871
9048
  globals: registry.allGlobals(),
8872
9049
  events: registry.allEvents()
8873
9050
  };
@@ -8885,6 +9062,7 @@ function ownDeclarations(registry, ambient) {
8885
9062
  classes: withoutNames(all.classes, ambient.classes),
8886
9063
  interfaces: withoutNames(all.interfaces, ambient.interfaces),
8887
9064
  enums: withoutNames(all.enums, ambient.enums),
9065
+ aliases: withoutNames(all.aliases, ambient.aliases),
8888
9066
  globals: withoutNames(all.globals, ambient.globals),
8889
9067
  events: withoutNames(all.events, ambient.events)
8890
9068
  };
@@ -8903,6 +9081,7 @@ function mergeAmbient(sources) {
8903
9081
  classes: mergeByName(sources.map((source) => source.classes)),
8904
9082
  interfaces: mergeByName(sources.map((source) => source.interfaces)),
8905
9083
  enums: mergeByName(sources.map((source) => source.enums)),
9084
+ aliases: mergeByName(sources.map((source) => source.aliases)),
8906
9085
  globals: mergeByName(sources.map((source) => source.globals)),
8907
9086
  events: mergeByName(sources.map((source) => source.events))
8908
9087
  };
@@ -8977,6 +9156,9 @@ function declareAll(catalog, environment, source) {
8977
9156
  function isAvailableIn(declared, environment) {
8978
9157
  return declared === "shared" || declared === environment;
8979
9158
  }
9159
+ function isVisibleIn(declared, environment) {
9160
+ return environment === "shared" || isAvailableIn(declared, environment);
9161
+ }
8980
9162
 
8981
9163
  // ../compiler/src/checker/api-types.ts
8982
9164
  var PRIMITIVES = {
@@ -9028,6 +9210,74 @@ function descriptorToType(descriptor) {
9028
9210
  return PRIMITIVES[descriptor.kind] ?? ANY_TYPE;
9029
9211
  }
9030
9212
 
9213
+ // ../compiler/src/checker/async.ts
9214
+ var PROMISE_TYPE = "Promise";
9215
+ var SLEEP_FUNCTION = "sleep";
9216
+ var PROMISE_PARAMETER = "T";
9217
+ var ORIGIN = { line: 0, column: 0, offset: 0 };
9218
+ var AWAIT_OUTSIDE_MESSAGE = '"await" is only valid inside an async function. Declare the function "async function name()", or wait on the promise with ":next(...)".';
9219
+ var ASYNC_ANNOTATION_MESSAGE = 'An async function is annotated with the type it resolves to, not with "Promise". Write the inner type and the signature becomes a promise of it.';
9220
+ var SLEEP_OUTSIDE_MESSAGE = '"sleep" suspends a coroutine and there is none here. Declare the function "async function name()", or run the body as a thread pool job.';
9221
+ function promiseOf(inner) {
9222
+ return createNamed(PROMISE_TYPE, [inner]);
9223
+ }
9224
+ function isPromiseType(type) {
9225
+ return (type.kind === "named" || type.kind === "record") && type.name === PROMISE_TYPE;
9226
+ }
9227
+ function declarePromiseType(declarations) {
9228
+ const value = createNamed(PROMISE_PARAMETER);
9229
+ const onFulfilled = createFunction([value], ANY_TYPE, 1, false, ["value"]);
9230
+ const onRejected = createFunction([ANY_TYPE], ANY_TYPE, 1, false, ["reason"]);
9231
+ const chained = promiseOf(ANY_TYPE);
9232
+ const next = createFunction([onFulfilled, createOptional(onRejected)], chained, 1, false, ["onFulfilled", "onRejected"]);
9233
+ const failure3 = createFunction([onRejected], chained, 1, false, ["onRejected"]);
9234
+ declarations.declareInterface({
9235
+ name: PROMISE_TYPE,
9236
+ isBuiltin: true,
9237
+ typeParameters: [PROMISE_PARAMETER],
9238
+ typeConstraints: [null],
9239
+ superInterfaces: [],
9240
+ members: /* @__PURE__ */ new Map([
9241
+ ["next", { name: "next", type: next, isMethod: true, position: ORIGIN }],
9242
+ ["catch", { name: "catch", type: failure3, isMethod: true, position: ORIGIN }]
9243
+ ]),
9244
+ position: ORIGIN
9245
+ });
9246
+ }
9247
+ function awaitedType(context, operand, expression) {
9248
+ if (!context.inAsyncBody()) {
9249
+ context.report("check-await-outside-async", AWAIT_OUTSIDE_MESSAGE, expression.position);
9250
+ return ANY_TYPE;
9251
+ }
9252
+ if (operand.kind === "any" || operand.kind === "unknown") {
9253
+ return ANY_TYPE;
9254
+ }
9255
+ if (isPromiseType(operand)) {
9256
+ return (operand.kind === "named" ? operand.typeArguments?.[0] : ANY_TYPE) ?? ANY_TYPE;
9257
+ }
9258
+ const message = `"await" expects a promise but received "${typeToString(operand)}". Only an async function or "new Promise(...)" produces one.`;
9259
+ context.report("check-await-non-promise", message, expression.position);
9260
+ return ANY_TYPE;
9261
+ }
9262
+ function isPromiseAnnotation(isAsync, annotation) {
9263
+ return isAsync && annotation !== null && annotation.kind === "type-name" && annotation.name === PROMISE_TYPE;
9264
+ }
9265
+ function asyncInnerAnnotation(isAsync, annotation) {
9266
+ return isPromiseAnnotation(isAsync, annotation) ? null : annotation;
9267
+ }
9268
+ function reportAsyncAnnotation(context, isAsync, annotation) {
9269
+ if (!isPromiseAnnotation(isAsync, annotation) || annotation === null) {
9270
+ return;
9271
+ }
9272
+ context.report("check-async-return-annotation", ASYNC_ANNOTATION_MESSAGE, annotation.position);
9273
+ }
9274
+ function reportSleepOutsideAsync(context, name, position2) {
9275
+ if (name !== SLEEP_FUNCTION || context.declaredGlobals.has(name) || context.binder.lookup(name)?.isLocal === true || context.suspendable()) {
9276
+ return;
9277
+ }
9278
+ context.warn("check-sleep-outside-async", SLEEP_OUTSIDE_MESSAGE, position2);
9279
+ }
9280
+
9031
9281
  // ../compiler/src/checker/binder.ts
9032
9282
  var Binder = class {
9033
9283
  scopes = [/* @__PURE__ */ new Map()];
@@ -9195,6 +9445,9 @@ var MAX_DEPTH = 32;
9195
9445
  function classSubstitutions(info, typeArguments) {
9196
9446
  return new Map(info.typeParameters.map((parameter, index) => [parameter, typeArguments[index] ?? ANY_TYPE]));
9197
9447
  }
9448
+ function parameterSubstitutions(typeParameters, typeArguments) {
9449
+ return new Map(typeParameters.map((parameter, index) => [parameter, typeArguments[index] ?? ANY_TYPE]));
9450
+ }
9198
9451
  function parentSubstitutions(registry, info, current) {
9199
9452
  const parent = info.superClass === null ? null : registry.lookupClass(info.superClass);
9200
9453
  if (parent === null) {
@@ -9222,7 +9475,15 @@ function substitutionsFor(registry, receiver, owner) {
9222
9475
  }
9223
9476
  return /* @__PURE__ */ new Map();
9224
9477
  }
9478
+ function interfaceSubstitutions(registry, receiver) {
9479
+ const contract = registry.lookupInterface(receiver.name);
9480
+ return contract === null ? null : parameterSubstitutions(contract.typeParameters, receiver.typeArguments ?? []);
9481
+ }
9225
9482
  function specializeMember(context, receiver, member, property) {
9483
+ const contract = interfaceSubstitutions(context.declarations, receiver);
9484
+ if (contract !== null) {
9485
+ return contract.size === 0 ? member : { ...member, type: substituteType(member.type, contract) };
9486
+ }
9226
9487
  const owner = context.declarations.lookupMemberOwner(receiver.name, property);
9227
9488
  if (owner === null || owner === receiver.name) {
9228
9489
  const own = context.declarations.lookupClass(receiver.name);
@@ -9307,6 +9568,11 @@ function reportConstraintViolations(context, owner, typeParameters, typeConstrai
9307
9568
  });
9308
9569
  }
9309
9570
  function checkTypeConstraints(context, name, typeArguments, position2) {
9571
+ const contract = context.declarations.lookupInterface(name);
9572
+ if (contract !== null) {
9573
+ reportConstraintViolations(context, `interface "${name}"`, contract.typeParameters, contract.typeConstraints, typeArguments, position2);
9574
+ return;
9575
+ }
9310
9576
  const info = context.declarations.lookupClass(name);
9311
9577
  if (info === null) {
9312
9578
  return;
@@ -9343,6 +9609,17 @@ var LUA_GLOBALS = {
9343
9609
  };
9344
9610
 
9345
9611
  // ../mta-types/src/luam-runtime.ts
9612
+ var PROMISE_VALUE = named("Promise");
9613
+ var RESOLVE = fn([ANY], VOID, 0, true, ["values"]);
9614
+ var REJECT = fn([ANY], VOID, 0, true, ["reason"]);
9615
+ var EXECUTOR = fn([RESOLVE, REJECT], ANY, 2, false, ["resolve", "reject"]);
9616
+ var ON_FULFILLED = fn([ANY], ANY, 0, true, ["value"]);
9617
+ var ON_REJECTED = fn([ANY], ANY, 1, false, ["reason"]);
9618
+ var PROMISE = record("Promise", [
9619
+ { name: "next", type: fn([ON_FULFILLED, optionalOf(ON_REJECTED)], PROMISE_VALUE, 1, false, ["onFulfilled", "onRejected"]) },
9620
+ { name: "catch", type: fn([ON_REJECTED], PROMISE_VALUE, 1, false, ["onRejected"]) }
9621
+ ]);
9622
+ var JOB = tupleOf([NUMBER, PROMISE]);
9346
9623
  var THREAD = record("Thread", [
9347
9624
  { name: "get", type: fn([], NUMBER, 0) },
9348
9625
  { name: "set", type: fn([NUMBER], BOOLEAN, 1) },
@@ -9351,8 +9628,10 @@ var THREAD = record("Thread", [
9351
9628
  { name: "isPaused", type: fn([], BOOLEAN, 0) },
9352
9629
  { name: "isStarted", type: fn([], BOOLEAN, 0) }
9353
9630
  ]);
9631
+ var JOB_BODY = fn([THREAD], ANY, 0, true, ["thread"]);
9632
+ var TASK_BODY = fn([ANY], ANY, 0, true, ["values"]);
9354
9633
  var THREADS = record("Threads", [
9355
- { name: "add", type: fn([ANY, TABLE], NUMBER, 1, true) },
9634
+ { name: "add", type: fn([JOB_BODY, TABLE], JOB, 1, true, ["target", "options"]) },
9356
9635
  { name: "remove", type: fn([NUMBER], BOOLEAN, 1) },
9357
9636
  { name: "clear", type: fn([], BOOLEAN, 0) },
9358
9637
  { name: "start", type: fn([], BOOLEAN, 0) },
@@ -9360,18 +9639,31 @@ var THREADS = record("Threads", [
9360
9639
  { name: "getType", type: fn([], STRING, 0) }
9361
9640
  ]);
9362
9641
  var ASYNC = record("Async", [
9363
- { name: "map", type: fn([TABLE, ANY, ANY], NUMBER, 2) },
9364
- { name: "iterate", type: fn([NUMBER, NUMBER, NUMBER, ANY, ANY], NUMBER, 4) },
9365
- { name: "foreach", type: fn([TABLE, ANY, ANY], NUMBER, 2) },
9642
+ { name: "map", type: fn([TABLE, ANY, ANY], JOB, 2) },
9643
+ { name: "iterate", type: fn([NUMBER, NUMBER, NUMBER, ANY, ANY], JOB, 4) },
9644
+ { name: "foreach", type: fn([TABLE, ANY, ANY], JOB, 2) },
9366
9645
  { name: "getInterval", type: fn([], NUMBER, 0) },
9367
9646
  { name: "setInterval", type: fn([NUMBER], BOOLEAN, 1) }
9368
9647
  ]);
9648
+ var PROMISE_LIBRARY = record("PromiseLibrary", [
9649
+ { name: "new", type: fn([EXECUTOR], PROMISE, 1, false, ["executor"]) },
9650
+ { name: "spawn", type: fn([TASK_BODY], PROMISE, 1, true, ["target"]) },
9651
+ { name: "resolve", type: fn([ANY], PROMISE, 0, true) },
9652
+ { name: "reject", type: fn([ANY], PROMISE, 0, true) },
9653
+ { name: "all", type: fn([arrayOf(ANY)], PROMISE, 1) },
9654
+ { name: "race", type: fn([arrayOf(ANY)], PROMISE, 1) },
9655
+ { name: "settle", type: fn([PROMISE], tupleOf([BOOLEAN, ANY]), 1) },
9656
+ { name: "await", type: fn([PROMISE], ANY, 1) },
9657
+ { name: "delay", type: fn([NUMBER], PROMISE, 1) }
9658
+ ]);
9369
9659
  var LUAM_RUNTIME_SERVER_GLOBALS = {};
9370
9660
  var LUAM_RUNTIME_GLOBALS = {
9371
9661
  bind: fn([ANY, ANY], ANY, 2),
9372
9662
  getClass: fn([STRING], optionalOf(TABLE), 1),
9373
9663
  getClasses: fn([], TABLE, 0),
9374
9664
  sleep: fn([NUMBER], ANY, 1),
9665
+ delay: fn([NUMBER], PROMISE, 1),
9666
+ Promise: PROMISE_LIBRARY,
9375
9667
  Thread: THREAD,
9376
9668
  Threads: record("ThreadsLibrary", [{ name: "new", type: fn([STRING, STRING], THREADS, 0) }]),
9377
9669
  Async: record("AsyncLibrary", [{ name: "new", type: fn([NUMBER], ASYNC, 0) }])
@@ -12233,10 +12525,14 @@ var MTA_EXACT = {
12233
12525
  client: MTA_CLIENT_GLOBALS
12234
12526
  };
12235
12527
  function globalsFor(environment) {
12236
- return DECLARATIONS.flatMap((declaration) => {
12528
+ const resolved2 = /* @__PURE__ */ new Map();
12529
+ for (const declaration of DECLARATIONS) {
12237
12530
  const exact = findDeclaration(declaration.name, environment);
12238
- return exact === null ? [] : [exact];
12239
- });
12531
+ if (exact !== null && !resolved2.has(exact.name)) {
12532
+ resolved2.set(exact.name, exact);
12533
+ }
12534
+ }
12535
+ return [...resolved2.values()];
12240
12536
  }
12241
12537
  function findDeclaration(name, environment) {
12242
12538
  const declaration = BY_NAME.get(name);
@@ -12244,7 +12540,7 @@ function findDeclaration(name, environment) {
12244
12540
  return declaration ?? null;
12245
12541
  }
12246
12542
  if (!isAvailableIn(declaration.environment, environment)) {
12247
- return null;
12543
+ return environment === "shared" ? declaration : null;
12248
12544
  }
12249
12545
  if (declaration.source !== "mta") {
12250
12546
  return declaration;
@@ -14049,11 +14345,15 @@ var DeclarationRegistry = class {
14049
14345
  classes = /* @__PURE__ */ new Map();
14050
14346
  interfaces = /* @__PURE__ */ new Map();
14051
14347
  enums = /* @__PURE__ */ new Map();
14348
+ aliases = /* @__PURE__ */ new Map();
14052
14349
  globals = /* @__PURE__ */ new Map();
14053
14350
  events = /* @__PURE__ */ new Map();
14054
14351
  declareGlobal(info) {
14055
14352
  this.globals.set(info.name, info);
14056
14353
  }
14354
+ lookupGlobal(name) {
14355
+ return this.globals.get(name) ?? null;
14356
+ }
14057
14357
  allGlobals() {
14058
14358
  return [...this.globals.values()];
14059
14359
  }
@@ -14089,6 +14389,15 @@ var DeclarationRegistry = class {
14089
14389
  declareEnum(info) {
14090
14390
  this.enums.set(info.name, info);
14091
14391
  }
14392
+ declareAlias(info) {
14393
+ this.aliases.set(info.name, info);
14394
+ }
14395
+ lookupAlias(name) {
14396
+ return this.aliases.get(name) ?? null;
14397
+ }
14398
+ allAliases() {
14399
+ return [...this.aliases.values()];
14400
+ }
14092
14401
  lookupEnum(name) {
14093
14402
  return this.enums.get(name) ?? null;
14094
14403
  }
@@ -14229,6 +14538,7 @@ function buildRegistry() {
14229
14538
  superClass: declaration.parent,
14230
14539
  superArguments: [],
14231
14540
  interfaces: [],
14541
+ interfaceArguments: [],
14232
14542
  members,
14233
14543
  statics: /* @__PURE__ */ new Map(),
14234
14544
  position: MTA_POSITION
@@ -14430,16 +14740,23 @@ var CheckContext = class {
14430
14740
  isDeclarationFile = false;
14431
14741
  returnStack = [];
14432
14742
  methodStack = [];
14743
+ functionStack = [];
14433
14744
  projectEnvironments = /* @__PURE__ */ new Map();
14434
14745
  predeclared = /* @__PURE__ */ new Map();
14435
14746
  ambientClasses = /* @__PURE__ */ new Set();
14436
14747
  ambientInterfaces = /* @__PURE__ */ new Set();
14437
14748
  ambientEnums = /* @__PURE__ */ new Set();
14749
+ ambientAliases = /* @__PURE__ */ new Set();
14750
+ ambientGlobals = /* @__PURE__ */ new Set();
14751
+ obligations = /* @__PURE__ */ new Map();
14752
+ blockDepth = 0;
14753
+ noImplicitGlobals = false;
14438
14754
  constructor(mode, environment, ambient = EMPTY_AMBIENT, project = EMPTY_PROJECT_DECLARATIONS, oop = false) {
14439
14755
  this.mode = mode;
14440
14756
  this.environment = environment;
14441
14757
  this.mtaClasses = oop ? mtaClassRegistry() : null;
14442
14758
  this.binder.useBuiltins(builtinSymbols(environment));
14759
+ declarePromiseType(this.declarations);
14443
14760
  this.declareProject(project);
14444
14761
  this.declareAmbient(ambient);
14445
14762
  }
@@ -14510,6 +14827,24 @@ var CheckContext = class {
14510
14827
  isAmbientEnum(name) {
14511
14828
  return this.ambientEnums.has(name);
14512
14829
  }
14830
+ isAmbientAlias(name) {
14831
+ return this.ambientAliases.has(name);
14832
+ }
14833
+ isAmbientGlobal(name) {
14834
+ return this.ambientGlobals.has(name);
14835
+ }
14836
+ openRecordObligation(obligation) {
14837
+ this.obligations.set(obligation.path, obligation);
14838
+ }
14839
+ recordObligation(path) {
14840
+ return this.obligations.get(path) ?? null;
14841
+ }
14842
+ closeRecordObligation(path) {
14843
+ this.obligations.delete(path);
14844
+ }
14845
+ recordObligationPaths() {
14846
+ return [...this.obligations.keys()];
14847
+ }
14513
14848
  noteExternalReference(name, position2) {
14514
14849
  if (!this.externalReferences.has(name)) {
14515
14850
  this.externalReferences.set(name, position2);
@@ -14595,6 +14930,18 @@ var CheckContext = class {
14595
14930
  currentClassMethod() {
14596
14931
  return this.methodStack[this.methodStack.length - 1] ?? null;
14597
14932
  }
14933
+ pushFunctionFrame(frame) {
14934
+ this.functionStack.push(frame);
14935
+ }
14936
+ popFunctionFrame() {
14937
+ this.functionStack.pop();
14938
+ }
14939
+ inAsyncBody() {
14940
+ return this.functionStack[this.functionStack.length - 1]?.isAsync === true;
14941
+ }
14942
+ suspendable() {
14943
+ return this.functionStack.some((frame) => frame.isAsync || frame.isExpression);
14944
+ }
14598
14945
  resolveAnnotation(annotation) {
14599
14946
  if (annotation === null) {
14600
14947
  return ANY_TYPE;
@@ -14679,19 +15026,28 @@ var CheckContext = class {
14679
15026
  assignability() {
14680
15027
  return { allowNil: this.allowNil, resolveNominal: (name) => this.nominalShape(name) };
14681
15028
  }
14682
- expectAssignable(source, target, position2, subject) {
15029
+ resolveValueAnnotation(annotation, subject) {
15030
+ const resolved2 = this.resolveAnnotation(annotation);
15031
+ if (resolved2.kind !== "tuple") {
15032
+ return resolved2;
15033
+ }
15034
+ const message = `A parenthesised list like "${typeToString(resolved2)}" is a return shape and cannot type ${subject}. Name one type instead.`;
15035
+ this.report("check-tuple-position", message, annotation.position);
15036
+ return firstValueOf(resolved2);
15037
+ }
15038
+ expectAssignable(source, target, position2, subject, printed = target) {
14683
15039
  if (isAssignable(source, target, this.assignability())) {
14684
15040
  return;
14685
15041
  }
14686
15042
  const received = isLiteralType(target) || target.kind === "union" ? source : widenLiteral(source);
14687
- const message = `${subject} expects "${typeToString(target)}" but received "${typeToString(received)}".`;
15043
+ const message = `${subject} expects "${typeToString(printed)}" but received "${typeToString(received)}".`;
14688
15044
  const hint = `${nilHint(source, target, this.mode)}${missingKeyHint(source, target, (name) => this.nominalShape(name))}`;
14689
15045
  this.report("check-type-mismatch", `${message}${hint}`, position2);
14690
15046
  }
14691
15047
  declareProject(project) {
14692
15048
  for (const declaration of project.globals) {
14693
15049
  this.projectEnvironments.set(declaration.name, declaration.environment);
14694
- if (isAvailableIn(declaration.environment, this.environment)) {
15050
+ if (isVisibleIn(declaration.environment, this.environment)) {
14695
15051
  const symbol = { name: declaration.name, type: descriptorToType(declaration.type), isLocal: false, position: PROJECT_POSITION };
14696
15052
  this.binder.declareGlobal(symbol);
14697
15053
  }
@@ -14712,7 +15068,14 @@ var CheckContext = class {
14712
15068
  this.declarations.declareEnum(info);
14713
15069
  this.binder.declareGlobal({ name: info.name, type: createNamed(info.name), isLocal: false, position: info.position });
14714
15070
  }
15071
+ for (const info of ambient.aliases) {
15072
+ this.ambientAliases.add(info.name);
15073
+ this.binder.declareAlias(info.name, info.type, info.typeParameters);
15074
+ this.declarations.declareAlias(info);
15075
+ }
14715
15076
  for (const info of ambient.globals) {
15077
+ this.ambientGlobals.add(info.name);
15078
+ this.declarations.declareGlobal(info);
14716
15079
  this.binder.declareGlobal({ name: info.name, type: info.type, isLocal: false, position: info.position });
14717
15080
  }
14718
15081
  for (const info of ambient.events) {
@@ -14732,18 +15095,20 @@ var CheckContext = class {
14732
15095
  return createMap(this.resolveAnnotation(key), this.resolveAnnotation(value));
14733
15096
  }
14734
15097
  resolveClassAnnotation(name, typeArguments, position2) {
14735
- const declared = this.declarations.lookupClass(name)?.typeParameters ?? [];
15098
+ const declaredInterface = this.declarations.lookupInterface(name);
15099
+ const owner = declaredInterface === null ? "Class" : "Interface";
15100
+ const declared = declaredInterface?.typeParameters ?? this.declarations.lookupClass(name)?.typeParameters ?? [];
14736
15101
  const resolved2 = typeArguments.map((argument) => this.resolveAnnotation(argument));
14737
15102
  if (declared.length === 0) {
14738
15103
  return createNamed(name);
14739
15104
  }
14740
15105
  if (resolved2.length !== declared.length) {
14741
15106
  const expected = declared.length === 1 ? "1 type argument" : `${declared.length} type arguments`;
14742
- this.report("check-generic-arity", `Class "${name}" expects ${expected} but received ${resolved2.length}.`, position2);
15107
+ this.report("check-generic-arity", `${owner} "${name}" expects ${expected} but received ${resolved2.length}.`, position2);
14743
15108
  }
14744
15109
  const specialized = createNamed(name, declared.map((unused, index) => resolved2[index] ?? ANY_TYPE));
14745
15110
  if (namedNesting(specialized) > MAX_GENERIC_DEPTH) {
14746
- const message = `Class "${name}" is nested more than ${MAX_GENERIC_DEPTH} levels deep here. Name the inner type with a "type" alias.`;
15111
+ const message = `${owner} "${name}" is nested more than ${MAX_GENERIC_DEPTH} levels deep here. Name the inner type with a "type" alias.`;
14747
15112
  this.report("check-generic-depth", message, position2);
14748
15113
  return createNamed(name);
14749
15114
  }
@@ -14789,6 +15154,7 @@ var ALLOWED = /* @__PURE__ */ new Set([
14789
15154
  var LABELS = {
14790
15155
  "local-statement": 'A "local" declaration',
14791
15156
  "assignment-statement": "An assignment",
15157
+ "global-statement": "A global declaration",
14792
15158
  "call-statement": "A call",
14793
15159
  "return-statement": 'A "return"',
14794
15160
  "break-statement": 'A "break"',
@@ -14837,6 +15203,7 @@ function childExpressions(expression) {
14837
15203
  case "binary-expression":
14838
15204
  return [expression.left, expression.right];
14839
15205
  case "unary-expression":
15206
+ case "await-expression":
14840
15207
  return [expression.operand];
14841
15208
  case "group-expression":
14842
15209
  return [expression.expression];
@@ -14848,6 +15215,7 @@ function statementExpressions(statement) {
14848
15215
  switch (statement.kind) {
14849
15216
  case "local-statement":
14850
15217
  case "return-statement":
15218
+ case "global-statement":
14851
15219
  return statement.values;
14852
15220
  case "assignment-statement":
14853
15221
  return [...statement.targets, ...statement.values];
@@ -14995,18 +15363,28 @@ function checkContract(context, info, contract, member) {
14995
15363
  const message = `${subject} expects "${typeToString(member.type)}" from interface "${contract}" but is "${typeToString(actual.type)}".`;
14996
15364
  context.report("check-unimplemented-interface", message, actual.position);
14997
15365
  }
15366
+ function contractName(name, typeArguments) {
15367
+ return typeArguments.length === 0 ? name : `${name}<${typeArguments.map(typeToString).join(", ")}>`;
15368
+ }
14998
15369
  function checkInterfaces(context, info) {
14999
- for (const name of info.interfaces) {
15370
+ info.interfaces.forEach((name, index) => {
15000
15371
  const contract = context.declarations.lookupInterface(name);
15001
15372
  if (contract === null) {
15002
15373
  context.noteExternalReference(name, info.position);
15003
15374
  context.report("check-unknown-interface", `Class "${info.name}" implements "${name}", which is not defined.`, info.position);
15004
- continue;
15375
+ return;
15376
+ }
15377
+ const typeArguments = info.interfaceArguments[index] ?? [];
15378
+ if (contract.typeParameters.length > 0 && typeArguments.length !== contract.typeParameters.length) {
15379
+ const expected = contract.typeParameters.length === 1 ? "1 type argument" : `${contract.typeParameters.length} type arguments`;
15380
+ context.report("check-generic-arity", `Interface "${name}" expects ${expected} but received ${typeArguments.length}.`, info.position);
15005
15381
  }
15382
+ const substitutions = parameterSubstitutions(contract.typeParameters, typeArguments);
15383
+ const label2 = contractName(name, typeArguments);
15006
15384
  for (const member of context.declarations.collectInterfaceContract(contract.name)) {
15007
- checkContract(context, info, name, member);
15385
+ checkContract(context, info, label2, substitutions.size === 0 ? member : { ...member, type: substituteType(member.type, substitutions) });
15008
15386
  }
15009
- }
15387
+ });
15010
15388
  }
15011
15389
  function checkOverrides(context, info, statement) {
15012
15390
  for (const member of statement.members) {
@@ -15401,6 +15779,7 @@ function accessorMethod(field2, decorator, name) {
15401
15779
  return {
15402
15780
  kind: "class-method",
15403
15781
  name,
15782
+ isAsync: false,
15404
15783
  isConstructor: false,
15405
15784
  isSynthetic: true,
15406
15785
  isStatic: false,
@@ -15414,7 +15793,7 @@ function accessorMethod(field2, decorator, name) {
15414
15793
  };
15415
15794
  }
15416
15795
  function generatedMethod(field2, name, parameters, returnAnnotation, kind, fields) {
15417
- return { kind: "class-method", name, isConstructor: false, isSynthetic: true, isStatic: false, typeParameters: [], typeConstraints: [], parameters, returnAnnotation, body: [], decorators: [], generated: { kind, fields }, position: field2.position };
15796
+ return { kind: "class-method", name, isAsync: false, isConstructor: false, isSynthetic: true, isStatic: false, typeParameters: [], typeConstraints: [], parameters, returnAnnotation, body: [], decorators: [], generated: { kind, fields }, position: field2.position };
15418
15797
  }
15419
15798
  function typeName(name, node) {
15420
15799
  return { kind: "type-name", name, typeArguments: [], position: node.position };
@@ -15449,6 +15828,7 @@ function staticMethod(statement, name, returnAnnotation, kind, descriptor) {
15449
15828
  return {
15450
15829
  kind: "class-method",
15451
15830
  name,
15831
+ isAsync: false,
15452
15832
  isConstructor: false,
15453
15833
  isSynthetic: true,
15454
15834
  isStatic: true,
@@ -15604,6 +15984,7 @@ function childExpressions2(expression) {
15604
15984
  case "binary-expression":
15605
15985
  return [expression.left, expression.right];
15606
15986
  case "unary-expression":
15987
+ case "await-expression":
15607
15988
  return [expression.operand];
15608
15989
  case "group-expression":
15609
15990
  return [expression.expression];
@@ -15615,6 +15996,7 @@ function statementExpressions2(statement) {
15615
15996
  switch (statement.kind) {
15616
15997
  case "local-statement":
15617
15998
  case "return-statement":
15999
+ case "global-statement":
15618
16000
  return statement.values;
15619
16001
  case "assignment-statement":
15620
16002
  return [...statement.targets, ...statement.values];
@@ -15672,6 +16054,9 @@ function addTargets(statement, paths) {
15672
16054
  if (statement.kind === "local-statement") {
15673
16055
  statement.declarations.forEach((declaration) => paths.add(declaration.name));
15674
16056
  }
16057
+ if (statement.kind === "global-statement") {
16058
+ paths.add(statement.declaration.name);
16059
+ }
15675
16060
  }
15676
16061
  function collectPaths(body, paths) {
15677
16062
  for (const statement of body) {
@@ -19083,21 +19468,42 @@ function eventHandler(name, environment) {
19083
19468
  return MTA_EVENT_SIGNATURES[environment][name] ?? null;
19084
19469
  }
19085
19470
 
19086
- // ../compiler/src/checker/environment-checks.ts
19087
- var EVENT_FUNCTIONS = /* @__PURE__ */ new Set(["addEventHandler", "removeEventHandler", "triggerEvent"]);
19471
+ // ../compiler/src/checker/environment-message.ts
19088
19472
  function scopeLabel(environment) {
19089
19473
  return environment === "shared" ? "shared" : `${environment}-only`;
19090
19474
  }
19475
+ function unavailableTail(environment) {
19476
+ return `is not available in a "${environment}" file.`;
19477
+ }
19478
+ function unusableTail(environment) {
19479
+ return `cannot be used in a "${environment}" file.`;
19480
+ }
19481
+ function reportEnvironment(context, code, message, position2) {
19482
+ if (context.environment === "shared") {
19483
+ return;
19484
+ }
19485
+ context.report(code, message, position2);
19486
+ }
19487
+
19488
+ // ../compiler/src/checker/environment-checks.ts
19489
+ var EVENT_FUNCTIONS = /* @__PURE__ */ new Set(["addEventHandler", "removeEventHandler", "triggerEvent"]);
19490
+ function reportProject(context, name, declared, position2) {
19491
+ const message = `"${name}" is declared by the project, is ${scopeLabel(declared)}, and ${unavailableTail(context.environment)}`;
19492
+ reportEnvironment(context, "check-environment-api", message, position2);
19493
+ }
19494
+ function reportApi(context, name, declared, position2) {
19495
+ const message = `API "${name}" is ${scopeLabel(declared)} and ${unavailableTail(context.environment)}`;
19496
+ reportEnvironment(context, "check-environment-api", message, position2);
19497
+ }
19091
19498
  function checkGlobalReference(context, name, position2) {
19092
19499
  if (name === "self") {
19093
- const message2 = 'A "self" is only bound inside a class method or a "function Name:method()"; here it reads a global that is "nil".';
19094
- context.report("check-invalid-self", message2, position2);
19500
+ const message = 'A "self" is only bound inside a class method or a "function Name:method()"; here it reads a global that is "nil".';
19501
+ context.report("check-invalid-self", message, position2);
19095
19502
  return;
19096
19503
  }
19097
19504
  const project = context.projectEnvironmentOf(name);
19098
19505
  if (project !== null) {
19099
- const message2 = `"${name}" is declared by the project, is ${scopeLabel(project)}, and is not available in a "${context.environment}" file.`;
19100
- context.report("check-environment-api", message2, position2);
19506
+ reportProject(context, name, project, position2);
19101
19507
  return;
19102
19508
  }
19103
19509
  const declared = declarationEnvironment(name);
@@ -19105,8 +19511,26 @@ function checkGlobalReference(context, name, position2) {
19105
19511
  context.noteExternalReference(name, position2);
19106
19512
  return;
19107
19513
  }
19108
- const message = `API "${name}" is ${scopeLabel(declared)} and is not available in a "${context.environment}" file.`;
19109
- context.report("check-environment-api", message, position2);
19514
+ reportApi(context, name, declared, position2);
19515
+ }
19516
+ function checkSharedReference(context, name, position2) {
19517
+ if (context.environment !== "shared" || context.moduleGlobals.has(name)) {
19518
+ return;
19519
+ }
19520
+ const project = context.projectEnvironmentOf(name);
19521
+ if (project !== null) {
19522
+ if (project !== "shared") {
19523
+ reportProject(context, name, project, position2);
19524
+ }
19525
+ return;
19526
+ }
19527
+ if (!context.binder.isBuiltinReference(name)) {
19528
+ return;
19529
+ }
19530
+ const declared = declarationEnvironment(name);
19531
+ if (declared !== null && declared !== "shared") {
19532
+ reportApi(context, name, declared, position2);
19533
+ }
19110
19534
  }
19111
19535
  function eventName(expression) {
19112
19536
  const argument = expression.args[0];
@@ -19125,8 +19549,8 @@ function checkEventUsage(context, expression) {
19125
19549
  if (name === null || custom?.environment === "shared" || custom?.environment === context.environment || declared === null || declared === context.environment) {
19126
19550
  return;
19127
19551
  }
19128
- const message = `Event "${name}" is ${scopeLabel(declared)} and cannot be used in a "${context.environment}" file.`;
19129
- context.report("check-environment-event", message, expression.position);
19552
+ const message = `Event "${name}" is ${scopeLabel(declared)} and ${unusableTail(context.environment)}`;
19553
+ reportEnvironment(context, "check-environment-event", message, expression.position);
19130
19554
  }
19131
19555
 
19132
19556
  // ../mta-types/src/event-call-semantics.ts
@@ -19307,6 +19731,136 @@ function withoutSelfParameter(signature2) {
19307
19731
  return createFunction(signature2.parameters.slice(1), signature2.returnType, minimum, signature2.isVariadic, names.slice(1), signature2.variadicType);
19308
19732
  }
19309
19733
 
19734
+ // ../compiler/src/checker/record-completion.ts
19735
+ function recordShapeOf(context, type) {
19736
+ if (type.kind === "record") {
19737
+ return type;
19738
+ }
19739
+ if (type.kind !== "named") {
19740
+ return null;
19741
+ }
19742
+ const shape = context.assignability().resolveNominal?.(type.name) ?? null;
19743
+ return shape === null ? null : { kind: "record", name: type.name, origin: null, members: shape.members };
19744
+ }
19745
+ function pendingKeys(context, source, target) {
19746
+ if (source.kind !== "record" || source.isLiteral !== true) {
19747
+ return null;
19748
+ }
19749
+ const shape = recordShapeOf(context, target);
19750
+ if (shape === null) {
19751
+ return null;
19752
+ }
19753
+ const missing2 = /* @__PURE__ */ new Map();
19754
+ const options = context.assignability();
19755
+ for (const [name, member] of shape.members) {
19756
+ const written = source.members.get(name);
19757
+ if (written === void 0) {
19758
+ if (member.kind !== "optional") {
19759
+ missing2.set(name, member);
19760
+ }
19761
+ continue;
19762
+ }
19763
+ if (!isAssignable(written, member, options)) {
19764
+ return null;
19765
+ }
19766
+ }
19767
+ for (const name of source.members.keys()) {
19768
+ if (!shape.members.has(name)) {
19769
+ return null;
19770
+ }
19771
+ }
19772
+ return missing2.size === 0 ? null : missing2;
19773
+ }
19774
+ function deferRecordCompletion(context, target, source, declared, subject, position2) {
19775
+ const path = pathOf2(target);
19776
+ if (path === null) {
19777
+ return false;
19778
+ }
19779
+ const missing2 = pendingKeys(context, source, declared);
19780
+ if (missing2 === null) {
19781
+ return false;
19782
+ }
19783
+ context.openRecordObligation({
19784
+ path,
19785
+ subject,
19786
+ source,
19787
+ target: declared,
19788
+ missing: missing2,
19789
+ discharged: 0,
19790
+ depth: context.blockDepth,
19791
+ line: position2.line,
19792
+ position: position2
19793
+ });
19794
+ return true;
19795
+ }
19796
+ function reportIncompleteRecord(context, obligation, position2) {
19797
+ if (obligation.discharged === 0) {
19798
+ context.closeRecordObligation(obligation.path);
19799
+ context.expectAssignable(obligation.source, obligation.target, obligation.position, obligation.subject);
19800
+ return;
19801
+ }
19802
+ const keys = [...obligation.missing.keys()].map((key) => `"${key}"`);
19803
+ const label2 = keys.length === 1 ? `Key ${keys[0]} is` : `Keys ${keys.join(", ")} are`;
19804
+ const built = `The table built on line ${obligation.line} is used before it is complete.`;
19805
+ const message = `${obligation.subject} expects "${typeToString(obligation.target)}". ${label2} never assigned. ${built}`;
19806
+ context.report("check-incomplete-record", message, position2);
19807
+ context.closeRecordObligation(obligation.path);
19808
+ }
19809
+ function dischargeRecordKey(context, target, valueType, position2) {
19810
+ if (target.kind !== "member-expression") {
19811
+ return false;
19812
+ }
19813
+ const path = pathOf2(target.object);
19814
+ const obligation = path === null ? null : context.recordObligation(path);
19815
+ if (obligation === null || obligation.depth !== context.blockDepth) {
19816
+ return false;
19817
+ }
19818
+ const expected = obligation.missing.get(target.property);
19819
+ if (expected === void 0) {
19820
+ return false;
19821
+ }
19822
+ context.expectAssignable(valueType, expected, position2, `Key "${target.property}"`);
19823
+ obligation.missing.delete(target.property);
19824
+ obligation.discharged += 1;
19825
+ if (obligation.missing.size === 0) {
19826
+ context.closeRecordObligation(obligation.path);
19827
+ }
19828
+ return true;
19829
+ }
19830
+ function extendInferredRecord(context, target, valueType) {
19831
+ if (target.kind !== "member-expression" || target.object.kind !== "identifier") {
19832
+ return false;
19833
+ }
19834
+ const symbol = context.binder.lookup(target.object.name);
19835
+ if (symbol === null || symbol.type.kind !== "record" || symbol.type.isInferred !== true || symbol.type.members.has(target.property)) {
19836
+ return false;
19837
+ }
19838
+ const members = new Map(symbol.type.members);
19839
+ members.set(target.property, widenInferred(valueType));
19840
+ const extended = createObjectType(members);
19841
+ symbol.type = extended.kind === "record" ? { ...extended, isInferred: true } : extended;
19842
+ return true;
19843
+ }
19844
+ function escapesRecordObligation(context, expression) {
19845
+ const path = pathOf2(expression);
19846
+ const obligation = path === null ? null : context.recordObligation(path);
19847
+ if (obligation !== null) {
19848
+ reportIncompleteRecord(context, obligation, expression.position);
19849
+ }
19850
+ }
19851
+ function settleRecordObligations(context, opened) {
19852
+ for (const path of context.recordObligationPaths()) {
19853
+ if (opened.has(path)) {
19854
+ continue;
19855
+ }
19856
+ const obligation = context.recordObligation(path);
19857
+ if (obligation === null) {
19858
+ continue;
19859
+ }
19860
+ reportIncompleteRecord(context, obligation, obligation.position);
19861
+ }
19862
+ }
19863
+
19310
19864
  // ../compiler/src/checker/resource-exports.ts
19311
19865
  var RESOURCE_LOOKUP = "getResourceFromName";
19312
19866
  var EXPORTS_TABLE = "exports";
@@ -19516,9 +20070,6 @@ function isElementType(name) {
19516
20070
 
19517
20071
  // ../compiler/src/checker/oop-members.ts
19518
20072
  var OOP_HINT = 'Set "compiler = { oop = true }" in .luam.manifest to enable the MTA OOP API.';
19519
- function scopeLabel2(environment) {
19520
- return environment === "shared" ? "shared" : `${environment}-only`;
19521
- }
19522
20073
  function isMtaElementName(declarations, className) {
19523
20074
  if (!isElementType(className)) {
19524
20075
  return false;
@@ -19536,6 +20087,14 @@ function reportDisabled(context, className, name, position2) {
19536
20087
  const subject = `"${className}.${name}" is part of the MTA OOP API, which this project does not enable.`;
19537
20088
  context.report("check-oop-disabled", `${subject} Call "${member.procedural}" instead. ${OOP_HINT}`, position2);
19538
20089
  }
20090
+ function acceptsMember(context, className, name, member, position2) {
20091
+ if (member.environment === void 0 || isAvailableIn(member.environment, context.environment)) {
20092
+ return true;
20093
+ }
20094
+ const subject = `"${className}.${name}" wraps "${member.procedural}", which is ${scopeLabel(member.environment)}`;
20095
+ reportEnvironment(context, "check-environment-api", `${subject} and ${unavailableTail(context.environment)}`, position2);
20096
+ return context.environment === "shared";
20097
+ }
19539
20098
  function isMtaClassReference(context, className) {
19540
20099
  return isMtaClass(className) && context.binder.lookup(className) === null && context.declarations.lookupClass(className) === null && context.declarations.lookupInterface(className) === null;
19541
20100
  }
@@ -19551,12 +20110,7 @@ function resolveMtaStaticMember(context, className, name, position2) {
19551
20110
  reportDisabled(context, className, name, position2);
19552
20111
  return null;
19553
20112
  }
19554
- if (member.environment !== void 0 && !isAvailableIn(member.environment, context.environment)) {
19555
- const subject = `"${className}.${name}" wraps "${member.procedural}", which is ${scopeLabel2(member.environment)}`;
19556
- context.report("check-environment-api", `${subject} and is not available in a "${context.environment}" file.`, position2);
19557
- return null;
19558
- }
19559
- return member;
20113
+ return acceptsMember(context, className, name, member, position2) ? member : null;
19560
20114
  }
19561
20115
  function resolveMtaConstructor(context, className, position2) {
19562
20116
  const constructor = mtaConstructor(className);
@@ -19571,9 +20125,11 @@ function resolveMtaConstructor(context, className, position2) {
19571
20125
  return null;
19572
20126
  }
19573
20127
  if (!isAvailableIn(constructor.environment, context.environment)) {
19574
- const subject = `"${className}(...)" is ${scopeLabel2(constructor.environment)}`;
19575
- context.report("check-environment-api", `${subject} and is not available in a "${context.environment}" file.`, position2);
19576
- return null;
20128
+ const subject = `"${className}(...)" is ${scopeLabel(constructor.environment)}`;
20129
+ reportEnvironment(context, "check-environment-api", `${subject} and ${unavailableTail(context.environment)}`, position2);
20130
+ if (context.environment !== "shared") {
20131
+ return null;
20132
+ }
19577
20133
  }
19578
20134
  return constructor.type;
19579
20135
  }
@@ -19593,12 +20149,7 @@ function resolveMtaMember(context, className, name, position2) {
19593
20149
  reportUnknown(context, className, name, position2);
19594
20150
  return null;
19595
20151
  }
19596
- if (member.environment !== void 0 && !isAvailableIn(member.environment, context.environment)) {
19597
- const subject = `"${className}.${name}" wraps "${member.procedural}", which is ${scopeLabel2(member.environment)}`;
19598
- context.report("check-environment-api", `${subject} and is not available in a "${context.environment}" file.`, position2);
19599
- return null;
19600
- }
19601
- return member;
20152
+ return acceptsMember(context, className, name, member, position2) ? member : null;
19602
20153
  }
19603
20154
 
19604
20155
  // ../compiler/src/checker/members.ts
@@ -19724,7 +20275,9 @@ function resolveNamedMember(context, receiver, expression) {
19724
20275
  if (contract === null) {
19725
20276
  return null;
19726
20277
  }
19727
- const members = new Map(context.declarations.collectMembers(name).map((member2) => [member2.name, member2]));
20278
+ const substitutions = parameterSubstitutions(contract.typeParameters, receiver.typeArguments ?? []);
20279
+ const collected = context.declarations.collectMembers(name).map((entry) => substitutions.size === 0 ? entry : { ...entry, type: substituteType(entry.type, substitutions) });
20280
+ const members = new Map(collected.map((entry) => [entry.name, entry]));
19728
20281
  return checkInterfaceMember(context, name, members, expression);
19729
20282
  }
19730
20283
  function reportUnknownMethod(context, receiver, callee, method, position2) {
@@ -19892,6 +20445,39 @@ function checkUnary(context, operator, operand, expression) {
19892
20445
  return context.record(expression, NUMBER_TYPE);
19893
20446
  }
19894
20447
 
20448
+ // ../compiler/src/checker/shadowing.ts
20449
+ var HELPER_TARGETS = new Map(
20450
+ NATIVE_EXTENSIONS.map((extension) => [
20451
+ extension.target,
20452
+ extension.style === "call" ? `${extension.receiver}.${extension.property}(...)` : `${extension.receiver}.${extension.property}`
20453
+ ])
20454
+ );
20455
+ var SUPPRESSION = 'Rename the declaration, or record the new signature in a ".d.luam" file so later calls are checked against it.';
20456
+ function reportShadowedGlobal(context, name, position2) {
20457
+ if (context.isDeclarationFile || !context.binder.isBuiltinReference(name)) {
20458
+ return;
20459
+ }
20460
+ const message = `"${name}" is an API this environment declares. Later calls are still checked against the declared signature, not this one. ${SUPPRESSION}`;
20461
+ context.warn("check-shadowed-api", message, position2);
20462
+ }
20463
+ function reportShadowedHelper(context, library, member, position2) {
20464
+ if (context.isDeclarationFile || !isLibrary(library) || findLibraryMember(library, member) === null) {
20465
+ return;
20466
+ }
20467
+ const target = `${library}.${member}`;
20468
+ const rewrite = HELPER_TARGETS.get(target);
20469
+ const lowered = rewrite === void 0 ? "" : ` The extension "${rewrite}" lowers to it.`;
20470
+ const message = `"${target}" is part of the standard library this build models.${lowered} Later calls are still checked against the declared signature, not this one. ${SUPPRESSION}`;
20471
+ context.warn("check-shadowed-helper", message, position2);
20472
+ }
20473
+ function reportImplicitGlobal(context, name, position2) {
20474
+ if (context.isDeclarationFile || !context.noImplicitGlobals) {
20475
+ return;
20476
+ }
20477
+ const message = `"${name}" is not declared anywhere this file can reach, so this assignment creates a global. Declare it with "local", annotate it as a global, or describe it in a ".d.luam" file.`;
20478
+ context.warn("check-implicit-global", message, position2);
20479
+ }
20480
+
19895
20481
  // ../compiler/src/checker/union-members.ts
19896
20482
  function isShapeOption(context, option) {
19897
20483
  if (option.kind === "record") {
@@ -20113,8 +20699,12 @@ function negatedFacts(context, condition) {
20113
20699
  // ../compiler/src/checker/control-flow.ts
20114
20700
  var ITERATOR_FUNCTIONS = /* @__PURE__ */ new Set(["pairs", "ipairs"]);
20115
20701
  function checkBlock(context, body) {
20702
+ const opened = new Set(context.recordObligationPaths());
20116
20703
  context.binder.pushScope();
20704
+ context.blockDepth += 1;
20117
20705
  checkStatements(context, body);
20706
+ context.blockDepth -= 1;
20707
+ settleRecordObligations(context, opened);
20118
20708
  const declared = context.binder.currentScopeNames();
20119
20709
  context.binder.popScope();
20120
20710
  for (const name of declared) {
@@ -20298,7 +20888,7 @@ function checkEventDeclaration(context, declaration) {
20298
20888
  }
20299
20889
 
20300
20890
  // ../compiler/src/checker/statements.ts
20301
- var ORIGIN = { line: 0, column: 0, offset: 0 };
20891
+ var ORIGIN2 = { line: 0, column: 0, offset: 0 };
20302
20892
  function minimumArguments(context, parameters) {
20303
20893
  const index = parameters.findIndex((parameter) => {
20304
20894
  const type = context.resolveAnnotation(parameter.annotation);
@@ -20306,12 +20896,17 @@ function minimumArguments(context, parameters) {
20306
20896
  });
20307
20897
  return index === -1 ? parameters.length : index;
20308
20898
  }
20309
- function buildFunctionType(context, parameters, returnAnnotation, contextual = null) {
20899
+ function buildFunctionType(context, parameters, returnAnnotation, contextual = null, isAsync = false) {
20310
20900
  const isVariadic = parameters.some((parameter) => parameter.isVararg);
20311
20901
  const named2 = parameters.filter((parameter) => !parameter.isVararg);
20312
- const types = named2.map((parameter, index) => parameter.annotation === null ? contextual?.parameters[index] ?? ANY_TYPE : context.resolveAnnotation(parameter.annotation));
20902
+ const types = named2.map(
20903
+ (parameter, index) => parameter.annotation === null ? contextual?.parameters[index] ?? ANY_TYPE : context.resolveValueAnnotation(parameter.annotation, "a parameter")
20904
+ );
20313
20905
  const names = named2.map((parameter) => parameter.name);
20314
- return createFunction(types, context.resolveAnnotation(returnAnnotation), minimumArguments(context, parameters), isVariadic, names);
20906
+ reportAsyncAnnotation(context, isAsync, returnAnnotation);
20907
+ const declared = context.resolveAnnotation(asyncInnerAnnotation(isAsync, returnAnnotation));
20908
+ const returnType = isAsync ? promiseOf(declared) : declared;
20909
+ return createFunction(types, returnType, minimumArguments(context, parameters), isVariadic, names);
20315
20910
  }
20316
20911
  function applyTypeParameters(context, type, names, constraints) {
20317
20912
  if (names.length === 0) {
@@ -20337,14 +20932,16 @@ function reportMissingReturn(context, declared, position2) {
20337
20932
  const repair = declared.kind === "tuple" ? "Add a return on every path." : `Add a return on every path, or declare "${name}?".`;
20338
20933
  context.report("check-missing-return", `This function declares "${name}" but can end without returning a value. ${repair}`, position2);
20339
20934
  }
20340
- function checkFunctionBody(context, parameters, returnAnnotation, body, signature2, selfType2, position2 = ORIGIN) {
20935
+ function checkFunctionBody(context, parameters, returnAnnotation, body, signature2, selfType2, position2 = ORIGIN2, frame = { isAsync: false, isExpression: false }) {
20341
20936
  forgetAssignedPaths(context, body);
20342
20937
  const entry = context.flowState;
20938
+ const annotation = asyncInnerAnnotation(frame.isAsync, returnAnnotation);
20343
20939
  context.setFlow(cloneFlow(entry));
20344
20940
  context.binder.pushScope();
20345
- context.pushReturnType(returnAnnotation === null ? null : context.resolveAnnotation(returnAnnotation));
20941
+ context.pushFunctionFrame(frame);
20942
+ context.pushReturnType(annotation === null ? null : context.resolveAnnotation(annotation));
20346
20943
  if (selfType2 !== null) {
20347
- context.binder.declare({ name: "self", type: selfType2, isLocal: true, position: ORIGIN });
20944
+ context.binder.declare({ name: "self", type: selfType2, isLocal: true, position: ORIGIN2 });
20348
20945
  }
20349
20946
  let parameterIndex = 0;
20350
20947
  for (const parameter of parameters) {
@@ -20354,15 +20951,20 @@ function checkFunctionBody(context, parameters, returnAnnotation, body, signatur
20354
20951
  parameterIndex += 1;
20355
20952
  }
20356
20953
  }
20954
+ const opened = new Set(context.recordObligationPaths());
20955
+ context.blockDepth += 1;
20357
20956
  checkStatements(context, body);
20957
+ context.blockDepth -= 1;
20958
+ settleRecordObligations(context, opened);
20358
20959
  const declared = context.currentReturnType();
20359
20960
  if (declared !== null && context.flowState.reachable && !toleratesFallthrough(declared)) {
20360
20961
  reportMissingReturn(context, declared, position2);
20361
20962
  }
20362
20963
  const inferred = context.popReturnType();
20363
- if (returnAnnotation === null) {
20364
- signature2.returnType = inferred;
20964
+ if (annotation === null) {
20965
+ signature2.returnType = frame.isAsync ? promiseOf(inferred) : inferred;
20365
20966
  }
20967
+ context.popFunctionFrame();
20366
20968
  context.binder.popScope();
20367
20969
  context.setFlow(entry);
20368
20970
  }
@@ -20383,9 +20985,11 @@ function checkLocal(context, statement) {
20383
20985
  context.binder.declare({ name: declaration.name, type: inferred, isLocal: true, position: declaration.position, origin: "local" });
20384
20986
  return;
20385
20987
  }
20386
- const declared = context.resolveAnnotation(declaration.annotation);
20387
- if (value !== void 0) {
20388
- context.expectAssignable(valueType, declared, value.position, `Variable "${declaration.name}"`);
20988
+ const declared = context.resolveValueAnnotation(declaration.annotation, "a local");
20989
+ const subject = `Variable "${declaration.name}"`;
20990
+ const deferred = value !== void 0 && deferRecordCompletion(context, { kind: "identifier", name: declaration.name, position: declaration.position }, valueType, declared, subject, value.position);
20991
+ if (value !== void 0 && !deferred) {
20992
+ context.expectAssignable(valueType, declared, value.position, subject);
20389
20993
  }
20390
20994
  context.binder.declare({ name: declaration.name, type: declared, isLocal: true, position: declaration.position, origin: "local" });
20391
20995
  if (value !== void 0) {
@@ -20404,6 +21008,13 @@ function checkCompoundOperand(context, operator, type, position2) {
20404
21008
  context.report("check-invalid-operand", `Operator "${operator}" cannot be applied to "${typeToString(type)}".`, position2);
20405
21009
  }
20406
21010
  }
21011
+ var DELETABLE_CONTAINERS = /* @__PURE__ */ new Set(["map", "array", "table"]);
21012
+ function deletesContainerKey(context, target, valueType) {
21013
+ if (valueType.kind !== "nil" || target.kind !== "index-expression" && target.kind !== "member-expression") {
21014
+ return false;
21015
+ }
21016
+ return DELETABLE_CONTAINERS.has(context.typeOf(target.object).kind);
21017
+ }
20407
21018
  function recordAssignedFact(context, path, valueType, declared) {
20408
21019
  if (path === null || valueType.kind === "any") {
20409
21020
  return;
@@ -20420,9 +21031,12 @@ function checkAssignment(context, statement) {
20420
21031
  if (assigned !== null) {
20421
21032
  context.forgetNarrowing(assigned);
20422
21033
  }
20423
- const targetType = checkExpression(context, target);
20424
21034
  const valueType = valueTypes[index] ?? NIL_TYPE;
20425
21035
  const value = valueAt(statement.values, valueTypes, index);
21036
+ if (value !== void 0 && extendInferredRecord(context, target, valueType)) {
21037
+ return;
21038
+ }
21039
+ const targetType = checkExpression(context, target);
20426
21040
  if (target.kind === "member-expression") {
20427
21041
  const object = context.typeOf(target.object);
20428
21042
  const frame = context.currentClassMethod();
@@ -20441,29 +21055,74 @@ function checkAssignment(context, statement) {
20441
21055
  return;
20442
21056
  }
20443
21057
  if (target.kind === "identifier" && context.binder.lookup(target.name) === null) {
21058
+ reportImplicitGlobal(context, target.name, target.position);
20444
21059
  context.declareModuleGlobal({ name: target.name, type: valueType, isLocal: false, position: target.position });
20445
21060
  return;
20446
21061
  }
21062
+ if (!context.insideFunction()) {
21063
+ reportShadowedAssignment(context, target);
21064
+ }
20447
21065
  const declared = target.kind === "identifier" ? context.binder.lookup(target.name)?.type ?? targetType : targetType;
21066
+ if (deletesContainerKey(context, target, valueType)) {
21067
+ return;
21068
+ }
21069
+ if (value !== void 0 && dischargeRecordKey(context, target, valueType, value.position)) {
21070
+ return;
21071
+ }
21072
+ const path = pathOf2(target);
21073
+ if (path !== null) {
21074
+ context.closeRecordObligation(path);
21075
+ }
21076
+ if (value !== void 0 && deferRecordCompletion(context, target, valueType, declared, "Assignment", value.position)) {
21077
+ return;
21078
+ }
20448
21079
  if (value !== void 0) {
20449
21080
  context.expectAssignable(valueType, declared, value.position, "Assignment");
20450
21081
  }
20451
21082
  recordAssignedFact(context, pathOf2(target), valueType, declared);
20452
21083
  });
20453
21084
  }
21085
+ function rootIdentifier(expression) {
21086
+ if (expression.kind === "identifier") {
21087
+ return expression.name;
21088
+ }
21089
+ return expression.kind === "member-expression" || expression.kind === "index-expression" ? rootIdentifier(expression.object) : null;
21090
+ }
21091
+ function reportShadowedAssignment(context, target) {
21092
+ if (target.kind !== "identifier") {
21093
+ const root = rootIdentifier(target);
21094
+ if (root !== null && context.binder.lookup(root) === null) {
21095
+ reportImplicitGlobal(context, root, target.position);
21096
+ }
21097
+ }
21098
+ if (target.kind === "identifier") {
21099
+ reportShadowedGlobal(context, target.name, target.position);
21100
+ return;
21101
+ }
21102
+ if (target.kind === "member-expression" && target.object.kind === "identifier") {
21103
+ reportShadowedHelper(context, target.object.name, target.property, target.position);
21104
+ }
21105
+ }
20454
21106
  function checkFunctionDeclaration(context, statement) {
20455
- const built = buildFunctionType(context, statement.parameters, statement.returnAnnotation);
21107
+ const built = buildFunctionType(context, statement.parameters, statement.returnAnnotation, null, statement.isAsync);
20456
21108
  const type = applyTypeParameters(context, built, statement.typeParameters, statement.typeConstraints);
20457
21109
  if (statement.name.kind === "identifier") {
20458
21110
  const symbol = { name: statement.name.name, type, isLocal: statement.isLocal, position: statement.position };
20459
21111
  if (statement.isLocal) {
20460
21112
  context.binder.declare({ ...symbol, origin: "local" });
20461
21113
  } else {
21114
+ reportShadowedGlobal(context, statement.name.name, statement.position);
20462
21115
  context.declareModuleGlobal(symbol);
20463
21116
  }
20464
21117
  }
21118
+ if (!statement.isLocal && statement.name.kind !== "identifier") {
21119
+ reportShadowedAssignment(context, statement.name);
21120
+ }
20465
21121
  context.record(statement.name, type);
20466
- checkFunctionBody(context, statement.parameters, statement.returnAnnotation, statement.body, type, statement.isMethod ? ANY_TYPE : null, statement.position);
21122
+ checkFunctionBody(context, statement.parameters, statement.returnAnnotation, statement.body, type, statement.isMethod ? ANY_TYPE : null, statement.position, {
21123
+ isAsync: statement.isAsync,
21124
+ isExpression: false
21125
+ });
20467
21126
  }
20468
21127
  function checkReturn(context, statement) {
20469
21128
  const valueTypes = checkValueList(context, statement.values);
@@ -20514,7 +21173,34 @@ function checkDeclareStatement(context, statement) {
20514
21173
  }
20515
21174
  const type = context.resolveAnnotation(statement.annotation);
20516
21175
  context.declareModuleGlobal({ name: statement.name, type, isLocal: false, position: statement.position });
20517
- context.declarations.declareGlobal({ name: statement.name, type, position: statement.position });
21176
+ context.declarations.declareGlobal({ name: statement.name, type, isDeclared: true, position: statement.position });
21177
+ }
21178
+ function checkGlobalStatement(context, statement) {
21179
+ const declaration = statement.declaration;
21180
+ const declared = declaration.annotation === null ? ANY_TYPE : context.resolveValueAnnotation(declaration.annotation, "a global");
21181
+ const valueTypes = checkValueList(context, statement.values);
21182
+ const value = valueAt(statement.values, valueTypes, 0);
21183
+ if (context.insideFunction()) {
21184
+ const message = `A type on global "${declaration.name}" is only valid at the top level of a file. Assign it without the annotation here.`;
21185
+ context.report("check-global-annotation-scope", message, statement.position);
21186
+ return;
21187
+ }
21188
+ const existing = context.declarations.lookupGlobal(declaration.name);
21189
+ const contract = existing !== null && existing.isDeclared === true ? existing.type : declared;
21190
+ if (existing !== null && existing.isDeclared !== true) {
21191
+ context.report("check-duplicate-global", `Global "${declaration.name}" is already declared with a type.`, statement.position);
21192
+ }
21193
+ if (value !== void 0) {
21194
+ context.expectAssignable(valueTypes[0] ?? NIL_TYPE, contract, value.position, `Global "${declaration.name}"`);
21195
+ }
21196
+ context.forgetNarrowing(declaration.name);
21197
+ context.declareModuleGlobal({ name: declaration.name, type: contract, isLocal: false, position: declaration.position });
21198
+ if (existing === null) {
21199
+ context.declarations.declareGlobal({ name: declaration.name, type: contract, position: declaration.position });
21200
+ }
21201
+ if (value !== void 0) {
21202
+ recordAssignedFact(context, declaration.name, valueTypes[0] ?? NIL_TYPE, contract);
21203
+ }
20518
21204
  }
20519
21205
  function checkStatement(context, statement) {
20520
21206
  switch (statement.kind) {
@@ -20522,6 +21208,8 @@ function checkStatement(context, statement) {
20522
21208
  return checkLocal(context, statement);
20523
21209
  case "assignment-statement":
20524
21210
  return checkAssignment(context, statement);
21211
+ case "global-statement":
21212
+ return checkGlobalStatement(context, statement);
20525
21213
  case "call-statement":
20526
21214
  checkExpression(context, statement.expression);
20527
21215
  return;
@@ -20548,11 +21236,15 @@ function checkStatement(context, statement) {
20548
21236
  case "generic-for-statement":
20549
21237
  return checkGenericFor(context, statement);
20550
21238
  case "type-alias-statement": {
20551
- const resolved2 = context.resolveAnnotation(statement.annotation);
21239
+ const resolved2 = context.resolveValueAnnotation(statement.annotation, "a type alias");
20552
21240
  const shape = statement.annotation.kind === "type-object" || statement.annotation.kind === "type-intersection";
20553
21241
  const named2 = shape ? renameRecord(resolved2, statement.name) : resolved2;
21242
+ if (context.isAmbientAlias(statement.name)) {
21243
+ context.report("check-duplicate-type", `Type "${statement.name}" is already defined.`, statement.position);
21244
+ }
20554
21245
  context.noteTypeParameters(statement.typeParameters);
20555
21246
  context.binder.declareAlias(statement.name, named2, statement.typeParameters);
21247
+ context.declarations.declareAlias({ name: statement.name, typeParameters: statement.typeParameters, type: named2, position: statement.position });
20556
21248
  return;
20557
21249
  }
20558
21250
  case "declare-statement":
@@ -20590,6 +21282,19 @@ function templateLiteralText(segments) {
20590
21282
  return segments.map((segment) => segment.kind === "text" ? segment.value : `\${${segment.value}}`).join("");
20591
21283
  }
20592
21284
 
21285
+ // ../compiler/src/checker/value-distribution.ts
21286
+ function distributeValueTypes(types) {
21287
+ const distributed = [];
21288
+ types.forEach((type, index) => {
21289
+ if (index === types.length - 1) {
21290
+ distributed.push(...valuesOf(type));
21291
+ return;
21292
+ }
21293
+ distributed.push(firstValueOf(type));
21294
+ });
21295
+ return distributed;
21296
+ }
21297
+
20593
21298
  // ../compiler/src/checker/expressions.ts
20594
21299
  var NAME_PATH_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/;
20595
21300
  var EXTENSION_RESULTS = {
@@ -20633,7 +21338,8 @@ function checkMember(context, expression) {
20633
21338
  checkExpression(context, expression.object);
20634
21339
  return context.record(expression, library);
20635
21340
  }
20636
- const objectType = checkExpression(context, expression.object);
21341
+ const received = checkExpression(context, expression.object);
21342
+ const objectType = received.kind === "optional" ? received.element : received;
20637
21343
  if (objectType.kind === "record") {
20638
21344
  return context.record(expression, resolveRecordMember(context, objectType, expression));
20639
21345
  }
@@ -20656,26 +21362,44 @@ function checkMember(context, expression) {
20656
21362
  }
20657
21363
  return context.record(expression, extension === null ? ANY_TYPE : EXTENSION_RESULTS[extension.result]);
20658
21364
  }
21365
+ function spreadsUnknownArity(args, argumentTypes) {
21366
+ if (args.length === 0 || args.length !== argumentTypes.length) {
21367
+ return false;
21368
+ }
21369
+ return args[args.length - 1]?.kind === "call-expression" && argumentTypes[argumentTypes.length - 1]?.kind === "any";
21370
+ }
21371
+ function resolveKeyedMember(context, objectType, expression) {
21372
+ if (expression.index.kind !== "string-literal" || objectType.kind !== "record" && objectType.kind !== "named") {
21373
+ return null;
21374
+ }
21375
+ const access = { kind: "member-expression", object: expression.object, property: expression.index.value, position: expression.index.position };
21376
+ return objectType.kind === "record" ? resolveRecordMember(context, objectType, access) : resolveNamedMember(context, objectType, access);
21377
+ }
20659
21378
  function countArguments2(total) {
20660
21379
  return total === 1 ? "1 argument" : `${total} arguments`;
20661
21380
  }
20662
21381
  function checkSignature(context, args, declared, position2, owner = "This call", typeArguments = []) {
20663
21382
  const argumentTypes = checkValueList(context, args, declared.parameters);
20664
21383
  const signature2 = specializeCall(context, owner, declared, argumentTypes, typeArguments, position2);
20665
- if (argumentTypes.length < signature2.minimumArguments) {
21384
+ const spreads = spreadsUnknownArity(args, argumentTypes);
21385
+ const fixed = spreads ? argumentTypes.length - 1 : argumentTypes.length;
21386
+ if (!spreads && argumentTypes.length < signature2.minimumArguments) {
20666
21387
  const message = `This call expects at least ${countArguments2(signature2.minimumArguments)} but received ${argumentTypes.length}.`;
20667
21388
  context.report("check-argument-count", message, position2);
20668
21389
  }
20669
- if (!signature2.isVariadic && argumentTypes.length > signature2.parameters.length) {
21390
+ if (!signature2.isVariadic && fixed > signature2.parameters.length) {
20670
21391
  const message = `This call expects at most ${countArguments2(signature2.parameters.length)} but received ${argumentTypes.length}.`;
20671
21392
  context.report("check-argument-count", message, position2);
20672
21393
  }
20673
21394
  signature2.parameters.forEach((parameter, index) => {
20674
21395
  const argumentType = argumentTypes[index];
20675
21396
  const argument = args[index];
20676
- if (argumentType !== void 0 && argument !== void 0) {
20677
- context.expectAssignable(argumentType, parameter, argument.position, `Argument ${index + 1}`);
21397
+ if (argumentType === void 0 || argument === void 0) {
21398
+ return;
20678
21399
  }
21400
+ const optional = index >= signature2.minimumArguments && parameter.kind !== "optional";
21401
+ const expected = optional ? createOptional(parameter) : parameter;
21402
+ context.expectAssignable(argumentType, expected, argument.position, `Argument ${index + 1}`, parameter);
20679
21403
  });
20680
21404
  if (signature2.isVariadic && signature2.variadicType !== void 0) {
20681
21405
  for (let index = signature2.parameters.length; index < argumentTypes.length; index += 1) {
@@ -20688,6 +21412,20 @@ function checkSignature(context, args, declared, position2, owner = "This call",
20688
21412
  }
20689
21413
  return signature2.returnType;
20690
21414
  }
21415
+ function reportClassReceiver(context, name, method, position2) {
21416
+ if (context.declarations.lookupStaticMember(name, method) !== null) {
21417
+ const message2 = `Call the static member "${method}" as "${name}.${method}(...)". A class value has no "self" to pass.`;
21418
+ context.report("check-static-receiver", message2, position2);
21419
+ return;
21420
+ }
21421
+ if (context.declarations.lookupMember(name, method) === null) {
21422
+ const message2 = `Call the static member "${method}" as "${name}.${method}(...)". A class value has no "self" to pass.`;
21423
+ context.report("check-static-receiver", message2, position2);
21424
+ return;
21425
+ }
21426
+ const message = `The receiver here is the class "${name}" itself, and "${method}" is one of its instance members. Create an instance \u2014 "local value = new ${name}()" \u2014 and call "value:${method}(...)", or read the member from a value of that class. Where the class and its single instance share one name, give the instance its own name.`;
21427
+ context.report("check-class-receiver", message, position2);
21428
+ }
20691
21429
  function callOwner(expression) {
20692
21430
  const name = expression.method ?? (expression.callee.kind === "identifier" ? expression.callee.name : null);
20693
21431
  return name === null ? "This call" : `Function "${name}"`;
@@ -20737,6 +21475,9 @@ function checkMethodCall(context, expression, method, receiver) {
20737
21475
  return checkSignature(context, expression.args, member.type, expression.position);
20738
21476
  }
20739
21477
  function checkCall(context, expression) {
21478
+ if (expression.method === null && expression.callee.kind === "identifier") {
21479
+ reportSleepOutsideAsync(context, expression.callee.name, expression.position);
21480
+ }
20740
21481
  const contracted = checkResourceCall(context, expression);
20741
21482
  if (contracted !== null) {
20742
21483
  return context.record(expression, contracted);
@@ -20759,9 +21500,7 @@ function checkCall(context, expression) {
20759
21500
  return context.record(expression, checkSignature(context, expression.args, constructor, expression.position));
20760
21501
  }
20761
21502
  if (expression.method !== null && expression.callee.kind === "identifier" && isUserClassReference(context, expression.callee.name)) {
20762
- const name = expression.callee.name;
20763
- const message = `Call the static member "${expression.method}" as "${name}.${expression.method}(...)". A class value has no "self" to pass.`;
20764
- context.report("check-static-receiver", message, expression.position);
21503
+ reportClassReceiver(context, expression.callee.name, expression.method, expression.position);
20765
21504
  checkValueList(context, expression.args);
20766
21505
  return context.record(expression, ANY_TYPE);
20767
21506
  }
@@ -20840,6 +21579,8 @@ function checkMultiValueExpression(context, expression, expected = null) {
20840
21579
  const symbol = context.binder.lookup(expression.name);
20841
21580
  if (symbol === null) {
20842
21581
  checkGlobalReference(context, expression.name, expression.position);
21582
+ } else {
21583
+ checkSharedReference(context, expression.name, expression.position);
20843
21584
  }
20844
21585
  if (symbol === null || symbol.isLocal !== true) {
20845
21586
  context.noteGlobalReference(expression.name);
@@ -20855,6 +21596,10 @@ function checkMultiValueExpression(context, expression, expected = null) {
20855
21596
  context.expectAssignable(indexType, objectType.key, expression.index.position, "Key");
20856
21597
  return context.record(expression, objectType.value);
20857
21598
  }
21599
+ const keyed = resolveKeyedMember(context, objectType, expression);
21600
+ if (keyed !== null) {
21601
+ return context.record(expression, keyed);
21602
+ }
20858
21603
  return context.record(expression, objectType.kind === "array" ? objectType.element : ANY_TYPE);
20859
21604
  }
20860
21605
  case "call-expression":
@@ -20864,9 +21609,12 @@ function checkMultiValueExpression(context, expression, expected = null) {
20864
21609
  case "table-expression":
20865
21610
  return checkTable(context, expression);
20866
21611
  case "function-expression": {
20867
- const built = buildFunctionType(context, expression.parameters, expression.returnAnnotation, contextualFunction(expected));
21612
+ const built = buildFunctionType(context, expression.parameters, expression.returnAnnotation, contextualFunction(expected), expression.isAsync);
20868
21613
  const type = applyTypeParameters(context, built, expression.typeParameters, expression.typeConstraints);
20869
- checkFunctionBody(context, expression.parameters, expression.returnAnnotation, expression.body, type, null, expression.position);
21614
+ checkFunctionBody(context, expression.parameters, expression.returnAnnotation, expression.body, type, null, expression.position, {
21615
+ isAsync: expression.isAsync,
21616
+ isExpression: true
21617
+ });
20870
21618
  return context.record(expression, type);
20871
21619
  }
20872
21620
  case "binary-expression": {
@@ -20876,6 +21624,8 @@ function checkMultiValueExpression(context, expression, expected = null) {
20876
21624
  }
20877
21625
  case "unary-expression":
20878
21626
  return checkUnary(context, expression.operator, checkExpression(context, expression.operand), expression);
21627
+ case "await-expression":
21628
+ return context.record(expression, awaitedType(context, checkExpression(context, expression.operand), expression));
20879
21629
  default:
20880
21630
  return context.record(expression, checkExpression(context, expression.expression, expected));
20881
21631
  }
@@ -20884,16 +21634,12 @@ function checkExpression(context, expression, expected = null) {
20884
21634
  return firstValueOf(checkMultiValueExpression(context, expression, expected));
20885
21635
  }
20886
21636
  function checkValueList(context, values, expected = []) {
20887
- const types = [];
20888
- values.forEach((value, index) => {
21637
+ const types = values.map((value, index) => {
20889
21638
  const type = checkMultiValueExpression(context, value, expected[index] ?? null);
20890
- if (index === values.length - 1) {
20891
- types.push(...valuesOf(type));
20892
- return;
20893
- }
20894
- types.push(firstValueOf(type));
21639
+ escapesRecordObligation(context, value);
21640
+ return type;
20895
21641
  });
20896
- return types;
21642
+ return distributeValueTypes(types);
20897
21643
  }
20898
21644
 
20899
21645
  // ../compiler/src/checker/classes.ts
@@ -20902,7 +21648,7 @@ function fieldType(context, member) {
20902
21648
  if (member.annotation === null) {
20903
21649
  return valueType === null ? ANY_TYPE : widenInferred(valueType);
20904
21650
  }
20905
- const declared = context.resolveAnnotation(member.annotation);
21651
+ const declared = context.resolveValueAnnotation(member.annotation, "a field");
20906
21652
  if (valueType !== null && member.value !== null) {
20907
21653
  context.expectAssignable(valueType, declared, member.value.position, `Field "${member.name}"`);
20908
21654
  }
@@ -20955,7 +21701,12 @@ function registerMembers(context, info, statement) {
20955
21701
  }
20956
21702
  const generated = expandClassDecorators(context, statement, fieldTypes);
20957
21703
  for (const member of [...statement.members, ...generated]) {
20958
- const type = member.kind === "class-field" ? fieldTypes.get(member) ?? ANY_TYPE : member.isSynthetic ? syntheticMethodType(context, member, fieldTypes) : applyTypeParameters(context, buildFunctionType(context, member.parameters, member.returnAnnotation), member.typeParameters, member.typeConstraints);
21704
+ const type = member.kind === "class-field" ? fieldTypes.get(member) ?? ANY_TYPE : member.isSynthetic ? syntheticMethodType(context, member, fieldTypes) : applyTypeParameters(
21705
+ context,
21706
+ buildFunctionType(context, member.parameters, member.returnAnnotation, null, member.isAsync),
21707
+ member.typeParameters,
21708
+ member.typeConstraints
21709
+ );
20959
21710
  const decorators = member.decorators.map((decorator) => decorator.name);
20960
21711
  if (member.kind === "class-method" && isMetamethodMember(member)) {
20961
21712
  checkMetamethod(context, info.name, member, type);
@@ -20996,6 +21747,7 @@ function declareBuilder(context, info, statement) {
20996
21747
  superClass: null,
20997
21748
  superArguments: [],
20998
21749
  interfaces: [],
21750
+ interfaceArguments: [],
20999
21751
  members,
21000
21752
  statics: /* @__PURE__ */ new Map(),
21001
21753
  position: statement.position
@@ -21014,17 +21766,19 @@ function checkMethodBody(context, info, member) {
21014
21766
  if (signature2?.kind !== "function") {
21015
21767
  return;
21016
21768
  }
21769
+ const frame = { isAsync: member.isAsync, isExpression: false };
21017
21770
  if (member.isStatic) {
21018
- checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body, signature2, null, member.position);
21771
+ checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body, signature2, null, member.position, frame);
21019
21772
  return;
21020
21773
  }
21021
21774
  context.pushClassMethod({ className: info.name, methodName: member.name });
21022
- checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body, signature2, selfType(info), member.position);
21775
+ checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body, signature2, selfType(info), member.position, frame);
21023
21776
  context.popClassMethod();
21024
21777
  }
21025
21778
  function assignSuperClass(context, info, statement) {
21026
- info.superClass = resolveSuperClass(context, statement);
21027
- info.hasUnresolvedParent = statement.superClass !== null && info.superClass === null;
21779
+ const resolved2 = resolveSuperClass(context, statement);
21780
+ info.superClass = resolved2 ?? statement.superClass;
21781
+ info.hasUnresolvedParent = statement.superClass !== null && resolved2 === null;
21028
21782
  }
21029
21783
  function resolveSuperClass(context, statement) {
21030
21784
  if (statement.superClass === null) {
@@ -21066,6 +21820,7 @@ function declareClassInfo(context, statement) {
21066
21820
  superClass: null,
21067
21821
  superArguments: [],
21068
21822
  interfaces: statement.interfaces,
21823
+ interfaceArguments: statement.interfaceArguments.map((args) => args.map((argument) => context.resolveAnnotation(argument))),
21069
21824
  members: /* @__PURE__ */ new Map(),
21070
21825
  statics: /* @__PURE__ */ new Map(),
21071
21826
  position: statement.position
@@ -21100,10 +21855,12 @@ function checkClassDeclaration(context, statement) {
21100
21855
  }
21101
21856
  }
21102
21857
  function checkInterfaceDeclaration(context, statement) {
21103
- if (context.declarations.lookupInterface(statement.name) !== null) {
21858
+ const existing = context.declarations.lookupInterface(statement.name);
21859
+ if (existing !== null && existing.isBuiltin !== true) {
21104
21860
  context.report("check-duplicate-interface", `Interface "${statement.name}" is already defined.`, statement.position);
21105
21861
  return;
21106
21862
  }
21863
+ context.noteTypeParameters(statement.typeParameters);
21107
21864
  const members = /* @__PURE__ */ new Map();
21108
21865
  for (const name of new Set(statement.superInterfaces)) {
21109
21866
  const parent = context.declarations.lookupInterface(name);
@@ -21120,7 +21877,7 @@ function checkInterfaceDeclaration(context, statement) {
21120
21877
  context.report("check-duplicate-interface-parent", `Interface "${statement.name}" extends the same interface more than once.`, statement.position);
21121
21878
  }
21122
21879
  for (const member of statement.members) {
21123
- const type = member.kind === "interface-field" ? context.resolveAnnotation(member.annotation) : buildFunctionType(context, member.parameters, member.returnAnnotation);
21880
+ const type = member.kind === "interface-field" ? context.resolveValueAnnotation(member.annotation, "a member") : buildFunctionType(context, member.parameters, member.returnAnnotation);
21124
21881
  const info = { name: member.name, type, isMethod: member.kind === "interface-method", position: member.position };
21125
21882
  if (members.has(member.name)) {
21126
21883
  context.report("check-duplicate-interface-member", `Interface "${statement.name}" declares member "${member.name}" more than once.`, member.position);
@@ -21131,16 +21888,18 @@ function checkInterfaceDeclaration(context, statement) {
21131
21888
  const inherited = /* @__PURE__ */ new Map();
21132
21889
  for (const parent of statement.superInterfaces) {
21133
21890
  for (const member of context.declarations.collectInterfaceContract(parent)) {
21134
- const existing = members.get(member.name) ?? inherited.get(member.name);
21135
- if (existing !== void 0 && (existing.isMethod !== member.isMethod || typeToString(existing.type) !== typeToString(member.type))) {
21891
+ const existing2 = members.get(member.name) ?? inherited.get(member.name);
21892
+ if (existing2 !== void 0 && (existing2.isMethod !== member.isMethod || typeToString(existing2.type) !== typeToString(member.type))) {
21136
21893
  context.report("check-conflicting-interface-member", `Interface "${statement.name}" inherits conflicting declarations of "${member.name}".`, statement.position);
21137
- } else if (existing === void 0) {
21894
+ } else if (existing2 === void 0) {
21138
21895
  inherited.set(member.name, member);
21139
21896
  }
21140
21897
  }
21141
21898
  }
21142
21899
  context.declarations.declareInterface({
21143
21900
  name: statement.name,
21901
+ typeParameters: statement.typeParameters,
21902
+ typeConstraints: statement.typeConstraints.map((constraint) => constraint === null ? null : context.resolveAnnotation(constraint)),
21144
21903
  superInterfaces: statement.superInterfaces,
21145
21904
  members,
21146
21905
  position: statement.position
@@ -21263,12 +22022,14 @@ function check(program2, mode, environment = DEFAULT_ENVIRONMENT, options = {})
21263
22022
  const ambient = options.ambient ?? EMPTY_AMBIENT;
21264
22023
  const project = options.project ?? EMPTY_PROJECT_DECLARATIONS;
21265
22024
  const context = new CheckContext(mode, environment, ambient, project, options.oop === true);
22025
+ context.noImplicitGlobals = options.noImplicitGlobals === true;
21266
22026
  context.isDeclarationFile = options.isDeclarationFile === true;
21267
22027
  context.contracts = options.contracts ?? [];
21268
22028
  const structure = context.isDeclarationFile ? checkDeclarationFile(program2.body) : checkJumps(program2.body);
21269
22029
  const directives = collectDirectives(program2.body, { isDeclarationFile: context.isDeclarationFile });
21270
22030
  predeclareModule(context, program2.body);
21271
22031
  checkStatements(context, program2.body);
22032
+ settleRecordObligations(context, /* @__PURE__ */ new Set());
21272
22033
  reportUnknownTypes(context);
21273
22034
  reportUnusedSymbols(context, options.noUnusedLocals === true, options.noUnusedParameters === true);
21274
22035
  const external = externalReferences(context);
@@ -21517,7 +22278,24 @@ function emitString(value) {
21517
22278
  function emitParameters(parameters) {
21518
22279
  return parameters.map((parameter) => parameter.isVararg ? "..." : parameter.name).join(", ");
21519
22280
  }
21520
- function emitFunctionBody(state, parameters, body, header) {
22281
+ function emitAsyncFunctionBody(state, parameters, body, header, receiver) {
22282
+ requireHelper(state, "promise");
22283
+ const declared = emitParameters(parameters);
22284
+ const forwarded = (receiver === null ? [declared] : [receiver, declared]).filter((part) => part.length > 0).join(", ");
22285
+ const previous = state.loopWrap;
22286
+ state.indent += 1;
22287
+ state.loopWrap = false;
22288
+ const lines = emitBlock(state, body);
22289
+ state.loopWrap = previous;
22290
+ state.indent -= 1;
22291
+ const signature2 = `${header}(${declared}) return Promise.spawn(function(${forwarded})`;
22292
+ const closing = indentLine(state, `end${forwarded.length === 0 ? "" : `, ${forwarded}`}) end`);
22293
+ return [signature2, ...lines, closing].join("\n");
22294
+ }
22295
+ function emitFunctionBody(state, parameters, body, header, isAsync = false, receiver = null) {
22296
+ if (isAsync) {
22297
+ return emitAsyncFunctionBody(state, parameters, body, header, receiver);
22298
+ }
21521
22299
  const previous = state.loopWrap;
21522
22300
  state.indent += 1;
21523
22301
  state.loopWrap = false;
@@ -21627,7 +22405,7 @@ function emitExpression(state, expression, limit = 0) {
21627
22405
  case "table-expression":
21628
22406
  return emitTable(state, expression);
21629
22407
  case "function-expression":
21630
- return emitFunctionBody(state, expression.parameters, expression.body, "function");
22408
+ return emitFunctionBody(state, expression.parameters, expression.body, "function", expression.isAsync);
21631
22409
  case "binary-expression":
21632
22410
  return emitBinary(state, expression, limit);
21633
22411
  case "unary-expression": {
@@ -21635,19 +22413,26 @@ function emitExpression(state, expression, limit = 0) {
21635
22413
  const text = expression.operator === "not" ? `not ${operand}` : `${expression.operator}${operand}`;
21636
22414
  return UNARY_PRECEDENCE < limit ? `(${text})` : text;
21637
22415
  }
22416
+ case "await-expression":
22417
+ requireHelper(state, "promise");
22418
+ return `Promise.await(${emitExpression(state, expression.operand)})`;
21638
22419
  default:
21639
22420
  return `(${emitExpression(state, expression.expression)})`;
21640
22421
  }
21641
22422
  }
21642
22423
 
21643
22424
  // ../compiler/src/emitter/classes.ts
22425
+ var BARE_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
22426
+ function emitMemberKey(name) {
22427
+ return BARE_KEY.test(name) ? name : `[${emitString(name)}]`;
22428
+ }
21644
22429
  function emitMethod(state, className, member) {
21645
22430
  const self = { name: "self", annotation: null, isVararg: false, position: member.position };
21646
22431
  if (member.generated !== void 0) {
21647
22432
  return emitGeneratedMethod(state, className, member);
21648
22433
  }
21649
22434
  const parameters = member.isStatic ? member.parameters : [self, ...member.parameters];
21650
- return withSymbol(state, `${className}${member.isStatic ? "." : ":"}${member.name}`, () => emitFunctionBody(state, parameters, member.body, `${member.name} = function`));
22435
+ return withSymbol(state, `${className}${member.isStatic ? "." : ":"}${member.name}`, () => emitFunctionBody(state, parameters, member.body, `${emitMemberKey(member.name)} = function`, member.isAsync));
21651
22436
  }
21652
22437
  function emitGeneratedMethod(state, className, member) {
21653
22438
  const fields = member.generated?.fields ?? [];
@@ -21733,7 +22518,7 @@ function emitMembers(state, statement) {
21733
22518
  continue;
21734
22519
  }
21735
22520
  const value = member.value === null ? "nil" : emitExpression(state, member.value);
21736
- entries3.push(indentLine(state, `${markSource(state, member.position.line, statement.name)}${member.name} = ${value}`));
22521
+ entries3.push(indentLine(state, `${markSource(state, member.position.line, statement.name)}${emitMemberKey(member.name)} = ${value}`));
21737
22522
  }
21738
22523
  for (const generated of state.generatedMembers.get(statement) ?? []) {
21739
22524
  entries3.push(indentLine(state, `${markSource(state, generated.position.line, `${statement.name}:${generated.name}`)}${emitMethod(state, statement.name, generated)}`));
@@ -21887,7 +22672,7 @@ function emitFunctionDeclaration(state, statement) {
21887
22672
  const prefix = statement.isLocal ? "local function " : "function ";
21888
22673
  const name = emitFunctionName(state, statement);
21889
22674
  const header = `${prefix}${name}`;
21890
- return withSymbol(state, name, () => emitFunctionBody(state, statement.parameters, statement.body, header));
22675
+ return withSymbol(state, name, () => emitFunctionBody(state, statement.parameters, statement.body, header, statement.isAsync, statement.isMethod ? "self" : null));
21891
22676
  }
21892
22677
  function emitNested2(state, body) {
21893
22678
  state.indent += 1;
@@ -21926,6 +22711,8 @@ function emitStatement(state, statement) {
21926
22711
  return emitLocal(state, statement);
21927
22712
  case "assignment-statement":
21928
22713
  return emitAssignment(state, statement);
22714
+ case "global-statement":
22715
+ return `${statement.declaration.name} = ${statement.values.map((value) => emitExpression(state, value)).join(", ")}`;
21929
22716
  case "call-statement":
21930
22717
  return emitExpression(state, statement.expression);
21931
22718
  case "function-declaration":
@@ -22099,6 +22886,7 @@ function fromExpression(expression, blocks) {
22099
22886
  fromExpression(expression.right, blocks);
22100
22887
  return;
22101
22888
  case "unary-expression":
22889
+ case "await-expression":
22102
22890
  fromExpression(expression.operand, blocks);
22103
22891
  return;
22104
22892
  case "group-expression":
@@ -22133,6 +22921,9 @@ function nestedBlocks(statement) {
22133
22921
  case "assignment-statement":
22134
22922
  fromExpressions([...statement.targets, ...statement.values], blocks);
22135
22923
  break;
22924
+ case "global-statement":
22925
+ fromExpressions(statement.values, blocks);
22926
+ break;
22136
22927
  case "call-statement":
22137
22928
  fromExpression(statement.expression, blocks);
22138
22929
  break;
@@ -22211,6 +23002,16 @@ function reindent(code, indent) {
22211
23002
  }
22212
23003
  return code.split("\n").map((line2, index) => index === 0 || line2.length === 0 ? line2 : `${indent}${line2}`).join("\n");
22213
23004
  }
23005
+ var CLOSING_LINE = /^\s*(?:end|\})/;
23006
+ function padAboveClosing(replacement, missing2) {
23007
+ const lines = replacement.split("\n");
23008
+ const closing = lines[lines.length - 1] ?? "";
23009
+ const blanks = Array.from({ length: missing2 }, () => "");
23010
+ if (lines.length < 2 || !CLOSING_LINE.test(closing)) {
23011
+ return [replacement, ...blanks].join("\n");
23012
+ }
23013
+ return [...lines.slice(0, -1), ...blanks, closing].join("\n");
23014
+ }
22214
23015
  function erasedEnd(source, span) {
22215
23016
  const trailing = TRAILING_SEMICOLON.exec(source.slice(span.end));
22216
23017
  return trailing === null ? span.end : span.end + trailing[0].length;
@@ -22233,7 +23034,7 @@ function canonicalEdit(input, statement, span) {
22233
23034
  if (missing2 < 0 && input.development) {
22234
23035
  return null;
22235
23036
  }
22236
- const padded = missing2 > 0 && source.slice(end).trim().length > 0 ? `${replacement}${"\n".repeat(missing2)}` : replacement;
23037
+ const padded = missing2 > 0 && source.slice(end).trim().length > 0 ? padAboveClosing(replacement, missing2) : replacement;
22237
23038
  return { start: span.start, end, replacement: padded, lines: emitted2.lines };
22238
23039
  }
22239
23040
 
@@ -22262,7 +23063,10 @@ function isPreservableExpression(expression, types, statics = NO_STATIC_ACCESS)
22262
23063
  switch (expression.kind) {
22263
23064
  case "template-literal":
22264
23065
  case "new-expression":
23066
+ case "await-expression":
22265
23067
  return false;
23068
+ case "function-expression":
23069
+ return !expression.isAsync;
22266
23070
  case "member-expression":
22267
23071
  return !statics.has(expression) && resolvePropertyExtension(types.get(expression.object) ?? null, expression.property) === null && isPreservableExpression(expression.object, types, statics);
22268
23072
  case "index-expression":
@@ -22311,11 +23115,12 @@ function isPreservableStatement(statement, types, statics = NO_STATIC_ACCESS) {
22311
23115
  return isPreservableExpression(statement.start, types, statics) && isPreservableExpression(statement.limit, types, statics) && (statement.step === null || isPreservableExpression(statement.step, types, statics));
22312
23116
  case "generic-for-statement":
22313
23117
  return every(statement.iterators, types, statics);
23118
+ case "function-declaration":
23119
+ return !statement.isAsync;
22314
23120
  case "break-statement":
22315
23121
  case "declare-statement":
22316
23122
  case "do-statement":
22317
23123
  case "event-declaration":
22318
- case "function-declaration":
22319
23124
  case "interface-declaration":
22320
23125
  case "type-alias-statement":
22321
23126
  return true;
@@ -22491,6 +23296,7 @@ function children(expression) {
22491
23296
  case "binary-expression":
22492
23297
  return [expression.left, expression.right];
22493
23298
  case "unary-expression":
23299
+ case "await-expression":
22494
23300
  return [expression.operand];
22495
23301
  case "group-expression":
22496
23302
  return [expression.expression];
@@ -22543,6 +23349,22 @@ function statementExpressions3(statement) {
22543
23349
  return null;
22544
23350
  }
22545
23351
  }
23352
+ function constructionEdit(input, expression, span) {
23353
+ const start = input.source.indexOf(expression.className, span.start);
23354
+ if (start === -1 || start >= span.end) {
23355
+ return null;
23356
+ }
23357
+ const isLibrary2 = input.types.get(expression)?.kind === "record";
23358
+ if (isLibrary2) {
23359
+ return { start: span.start, end: start + expression.className.length, replacement: `${expression.className}.new` };
23360
+ }
23361
+ const spacing = /^[ \t]*/.exec(input.source.slice(start + expression.className.length))?.[0] ?? "";
23362
+ return {
23363
+ start: span.start,
23364
+ end: start + expression.className.length + spacing.length,
23365
+ replacement: `new ${emitString(expression.className)} `
23366
+ };
23367
+ }
22546
23368
  function expressionEdits(input, statement) {
22547
23369
  const slots = input.development ? statementExpressions3(statement) : null;
22548
23370
  if (slots === null) {
@@ -22555,7 +23377,18 @@ function expressionEdits(input, statement) {
22555
23377
  const edits = [];
22556
23378
  for (const expression of found) {
22557
23379
  const span = input.spans.get(expression);
22558
- if (span === void 0 || holdsFunction(expression)) {
23380
+ if (span === void 0) {
23381
+ return null;
23382
+ }
23383
+ if (expression.kind === "new-expression") {
23384
+ const edit = constructionEdit(input, expression, span);
23385
+ if (edit === null) {
23386
+ return null;
23387
+ }
23388
+ edits.push(edit);
23389
+ continue;
23390
+ }
23391
+ if (holdsFunction(expression)) {
22559
23392
  return null;
22560
23393
  }
22561
23394
  const state = createEmitState(input.types, input.references, input.generatedMembers, input.staticAccess);
@@ -22824,6 +23657,7 @@ function compile(source, options = {}) {
22824
23657
  isDeclarationFile,
22825
23658
  oop: settings.oop,
22826
23659
  noUnusedLocals: settings.noUnusedLocals,
23660
+ noImplicitGlobals: settings.noImplicitGlobals,
22827
23661
  noUnusedParameters: settings.noUnusedParameters
22828
23662
  });
22829
23663
  const diagnostics = sortDiagnostics([...parsed.diagnostics, ...resolved2.diagnostics, ...checked.diagnostics]);
@@ -23067,11 +23901,12 @@ function createDependencyGraph(nodes) {
23067
23901
 
23068
23902
  // ../compiler/src/project/ambient-scope.ts
23069
23903
  function optionsKey(options) {
23070
- return `${options.strict ? "strict" : ""}|${options.oop ? "oop" : ""}|${options.noUnusedLocals ? "nul" : ""}|${options.noUnusedParameters ? "nup" : ""}`;
23904
+ const flags = [options.strict ? "strict" : "", options.oop ? "oop" : "", options.noUnusedLocals ? "nul" : "", options.noUnusedParameters ? "nup" : ""];
23905
+ return `${flags.join("|")}|${options.noImplicitGlobals ? "nig" : ""}`;
23071
23906
  }
23072
23907
  function declaresNothing(declarations) {
23073
- const { classes, interfaces, enums, globals, events } = declarations;
23074
- return classes.length === 0 && interfaces.length === 0 && enums.length === 0 && globals.length === 0 && events.length === 0;
23908
+ const { classes, interfaces, enums, aliases, globals, events } = declarations;
23909
+ return classes.length === 0 && interfaces.length === 0 && enums.length === 0 && aliases.length === 0 && globals.length === 0 && events.length === 0;
23075
23910
  }
23076
23911
  function sharedEnums(collected) {
23077
23912
  const declared = new Set(collected.flatMap((entry) => entry.declarations.enums.map((enumeration) => enumeration.name)));