@tilua/parser 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -4498,7 +4498,12 @@ function substitute(t, subst) {
4498
4498
  return t.name && r.kind === "intersection" && !r.name ? { ...r, name: t.name } : r;
4499
4499
  }
4500
4500
  case "genericRef":
4501
- return { kind: "genericRef", name: t.name, typeArguments: t.typeArguments.map((a) => substitute(a, subst)) };
4501
+ return {
4502
+ kind: "genericRef",
4503
+ name: t.name,
4504
+ typeArguments: t.typeArguments.map((a) => substitute(a, subst)),
4505
+ ...t.origin ? { origin: t.origin } : {}
4506
+ };
4502
4507
  case "keyof":
4503
4508
  return { kind: "keyof", target: substitute(t.target, subst) };
4504
4509
  case "templateLiteral":
@@ -4658,6 +4663,7 @@ function optional(t) {
4658
4663
  return union([t, nilType]);
4659
4664
  }
4660
4665
  function widen(t) {
4666
+ if (isAliasNamed(t)) return t;
4661
4667
  switch (t.kind) {
4662
4668
  case "literal":
4663
4669
  return primitive(t.base);
@@ -4697,7 +4703,7 @@ function isAssignable(rawA, rawB) {
4697
4703
  if (expandAlias) {
4698
4704
  if (a.kind === "genericRef" && b.kind !== "genericRef") a = expandAlias(a);
4699
4705
  else if (b.kind === "genericRef" && a.kind !== "genericRef") b = expandAlias(b);
4700
- else if (a.kind === "genericRef" && b.kind === "genericRef" && a.name !== b.name) {
4706
+ else if (a.kind === "genericRef" && b.kind === "genericRef" && !sameRefTarget(a, b)) {
4701
4707
  a = expandAlias(a);
4702
4708
  b = expandAlias(b);
4703
4709
  }
@@ -4807,10 +4813,17 @@ function isAssignableInner(a, b) {
4807
4813
  }
4808
4814
  if (b.kind === "typeParam") return false;
4809
4815
  if (a.kind === "genericRef" || b.kind === "genericRef") {
4810
- return a.kind === "genericRef" && b.kind === "genericRef" && a.name === b.name && a.typeArguments.length === b.typeArguments.length && a.typeArguments.every((x, i) => equalTypes(x, b.typeArguments[i]));
4816
+ return a.kind === "genericRef" && b.kind === "genericRef" && sameRefTarget(a, b) && a.typeArguments.length === b.typeArguments.length && a.typeArguments.every((x, i) => equalTypes(x, b.typeArguments[i]));
4811
4817
  }
4812
4818
  return false;
4813
4819
  }
4820
+ function isAliasNamed(t) {
4821
+ if (t.kind === "object" || t.kind === "intersection") return t.name !== void 0;
4822
+ return t.alias !== void 0;
4823
+ }
4824
+ function sameRefTarget(a, b) {
4825
+ return a.name === b.name && (!a.origin || !b.origin || a.origin === b.origin);
4826
+ }
4814
4827
  function isNoValue(t) {
4815
4828
  return t.kind === "tuple" && t.elements.length === 0;
4816
4829
  }
@@ -5211,6 +5224,7 @@ function mergeObjectMembers(types) {
5211
5224
  var INTERNAL_MEMBERS = /* @__PURE__ */ new Set(["ClassObject", "ParentClass"]);
5212
5225
  var MAX_MISSING = 3;
5213
5226
  var MAX_EXPLANATION = 90;
5227
+ var MAX_TYPE = 120;
5214
5228
  function analyzeTypes(program, scopes, options = {}) {
5215
5229
  return new TypeAnalyzer(program, scopes, options).run();
5216
5230
  }
@@ -5589,11 +5603,15 @@ var TypeAnalyzer = class {
5589
5603
  narrowedTypeOf = /* @__PURE__ */ new Map();
5590
5604
  typeOfTypeNode = /* @__PURE__ */ new Map();
5591
5605
  expectedTypeOf = /* @__PURE__ */ new Map();
5606
+ iteratesValues = /* @__PURE__ */ new Set();
5592
5607
  /** Public: each alias resolved once (generic aliases keep their params as
5593
5608
  * `typeParam` nodes in the body). */
5594
5609
  aliases = new AliasMap();
5595
5610
  /** Uninstantiated alias definitions, for `Name<Args>` instantiation. */
5596
5611
  aliasDefs = /* @__PURE__ */ new Map();
5612
+ /** Put on every ref to one of `aliasDefs`, so a module that imports the
5613
+ * type expands the ref here rather than by its name there. */
5614
+ origin = { expand: (t) => this.expand(t) };
5597
5615
  /** See `resolveClass`. */
5598
5616
  classTypes = /* @__PURE__ */ new WeakMap();
5599
5617
  /** See `instanceType` — one instance type per `class ... end`. */
@@ -5669,6 +5687,7 @@ var TypeAnalyzer = class {
5669
5687
  typeOfTypeNode: this.typeOfTypeNode,
5670
5688
  expectedTypeOf: this.expectedTypeOf,
5671
5689
  aliases: this.resolveDeferredAliases(),
5690
+ iteratesValues: this.iteratesValues,
5672
5691
  diagnostics: this.diagnostics
5673
5692
  };
5674
5693
  }
@@ -6001,7 +6020,8 @@ var TypeAnalyzer = class {
6001
6020
  return {
6002
6021
  kind: "genericRef",
6003
6022
  name: stmt.name.name,
6004
- typeArguments: params.map((p) => typeParam(p.name, p.constraint ? this.resolveType(p.constraint) : void 0))
6023
+ typeArguments: params.map((p) => typeParam(p.name, p.constraint ? this.resolveType(p.constraint) : void 0)),
6024
+ origin: this.origin
6005
6025
  };
6006
6026
  }
6007
6027
  /** The class table: the statics, what it inherits from the class it
@@ -6162,7 +6182,7 @@ var TypeAnalyzer = class {
6162
6182
  if (declared && this.emitDiagnostics && !isAssignable(actual, declared)) {
6163
6183
  this.diagnostics.push({
6164
6184
  node: member.init,
6165
- message: `Type '${formatType(actual)}' is not assignable to type '${formatType(declared)}'` + this.explainMismatch(actual, declared)
6185
+ message: `Type '${briefType(actual)}' is not assignable to type '${briefType(declared)}'` + this.explainMismatch(actual, declared)
6166
6186
  });
6167
6187
  }
6168
6188
  continue;
@@ -6349,7 +6369,7 @@ var TypeAnalyzer = class {
6349
6369
  if (fits) return;
6350
6370
  this.diagnostics.push({
6351
6371
  node: stmt,
6352
- message: `Type '${formatType(actual)}' is not assignable to '${briefType(declared)}'` + this.explainMismatch(actual, declared)
6372
+ message: `Type '${briefType(actual)}' is not assignable to '${briefType(declared)}'` + this.explainMismatch(actual, declared)
6353
6373
  });
6354
6374
  }
6355
6375
  /** A function that declared what it returns but never does. Only a body
@@ -6566,7 +6586,8 @@ var TypeAnalyzer = class {
6566
6586
  return this.expand({
6567
6587
  kind: "genericRef",
6568
6588
  name: node.base,
6569
- typeArguments: node.typeArguments.map((a) => this.resolveType(a))
6589
+ typeArguments: node.typeArguments.map((a) => this.resolveType(a)),
6590
+ origin: this.origin
6570
6591
  });
6571
6592
  }
6572
6593
  const imported = this.importedTypes.get(node.base);
@@ -6579,7 +6600,8 @@ var TypeAnalyzer = class {
6579
6600
  return this.expand({
6580
6601
  kind: "genericRef",
6581
6602
  name,
6582
- typeArguments: node.typeArguments.map((a) => this.resolveType(a))
6603
+ typeArguments: node.typeArguments.map((a) => this.resolveType(a)),
6604
+ origin: this.origin
6583
6605
  });
6584
6606
  }
6585
6607
  return {
@@ -7009,7 +7031,7 @@ var TypeAnalyzer = class {
7009
7031
  if (declared.kind !== "any" && !this.namesNothing(declared) && !this.fitsAnnotation(source, declared, inferred, env)) {
7010
7032
  this.diagnostics.push({
7011
7033
  node: stmt,
7012
- message: `Type '${formatType(inferred)}' is not assignable to '${formatType(declared)}'` + this.explainMismatch(inferred, declared)
7034
+ message: `Type '${briefType(inferred)}' is not assignable to '${briefType(declared)}'` + this.explainMismatch(inferred, declared)
7013
7035
  });
7014
7036
  } else if (declared.kind !== "any") {
7015
7037
  this.reportExcessProperties(source, declared);
@@ -7103,7 +7125,7 @@ var TypeAnalyzer = class {
7103
7125
  if (this.emitDiagnostics && !isAssignable(next, declared) && declared.kind !== "any") {
7104
7126
  this.diagnostics.push({
7105
7127
  node: stmt,
7106
- message: `Type '${formatType(next)}' is not assignable to '${formatType(declared)}'` + this.explainMismatch(next, declared)
7128
+ message: `Type '${briefType(next)}' is not assignable to '${briefType(declared)}'` + this.explainMismatch(next, declared)
7107
7129
  });
7108
7130
  }
7109
7131
  this.setBinding(env, id, narrowTo(declared, next));
@@ -7188,21 +7210,23 @@ var TypeAnalyzer = class {
7188
7210
  const valueId = value.type === "IdentifierPattern" ? this.bindingIdByName(value.name, value) : void 0;
7189
7211
  if (keyId !== void 0 && valueId !== void 0) this.correlateBindings(bodyEnv, [keyId, valueId], rows);
7190
7212
  } else {
7191
- const [keyT, valT] = this.iterationTypes(stmt.iterators[0], iterTypes[0], stmt.variables.length);
7213
+ const [keyT, valT, iteratesValues] = this.iterationTypes(stmt.iterators[0], iterTypes[0], stmt.variables.length);
7192
7214
  stmt.variables.forEach((v, i) => {
7193
7215
  this.bindPattern(v, i === 0 ? keyT : i === 1 ? valT : unknownType, bodyEnv, "widen");
7194
7216
  });
7217
+ if (iteratesValues && stmt.iterators.length === 1) this.iteratesValues.add(stmt);
7195
7218
  }
7196
7219
  this.visitBlock(stmt.body, bodyEnv);
7197
7220
  return;
7198
7221
  }
7199
7222
  case "ReturnStatement": {
7200
7223
  const declared = this.declaredReturns[this.declaredReturns.length - 1];
7201
- if (declared) {
7224
+ const wanted = declared ?? this.contextualReturns[this.contextualReturns.length - 1];
7225
+ if (wanted) {
7202
7226
  if (stmt.arguments.length === 1) {
7203
- this.applyContext(stmt.arguments[0], declared);
7204
- } else if (declared.kind === "tuple" && declared.isPack) {
7205
- stmt.arguments.forEach((a, i) => this.applyContext(a, declared.elements[i]));
7227
+ this.applyContext(stmt.arguments[0], wanted);
7228
+ } else if (wanted.kind === "tuple" && wanted.isPack) {
7229
+ stmt.arguments.forEach((a, i) => this.applyContext(a, wanted.elements[i]));
7206
7230
  }
7207
7231
  }
7208
7232
  const want = declared?.kind === "tuple" && declared.isPack ? declared.elements.length : 0;
@@ -7431,6 +7455,17 @@ var TypeAnalyzer = class {
7431
7455
  /** What a function expression's unannotated parameters are, from where
7432
7456
  * it is written — see `applyContext`. */
7433
7457
  contextualParams = /* @__PURE__ */ new WeakMap();
7458
+ /** What a function expression written in a typed position returns, from
7459
+ * that position — see `applyContext`. A body with no `return` annotation
7460
+ * would otherwise infer its `return` expressions with nothing wanted of
7461
+ * them, and widen the literals in them: `() => S = function() { return
7462
+ * { Status: true } }` inferred `Status: boolean` and then failed against
7463
+ * `S`. It is a hint, not a contract: only `applyContext` reads it, so a
7464
+ * body that does not match still reports at the assignment, not here. */
7465
+ contextualReturnOf = /* @__PURE__ */ new WeakMap();
7466
+ /** `contextualReturnOf` for each function body being walked, alongside
7467
+ * `declaredReturns`. */
7468
+ contextualReturns = [];
7434
7469
  /** `expected` is the type the surroundings want for `expr`. A function
7435
7470
  * expression written there takes its unannotated parameters' types from
7436
7471
  * it, as in TypeScript: `signal:Connect(function(player) ... end)` knows
@@ -7453,6 +7488,10 @@ var TypeAnalyzer = class {
7453
7488
  const members = expected.kind === "union" ? expected.types : [expected];
7454
7489
  const signatures = members.flatMap((m) => this.overloadsOf(this.expand(m)));
7455
7490
  if (!signatures.length) return;
7491
+ if (!e.func.returnType && !e.func.predicate) {
7492
+ const returns = signatures.map((s) => s.returns).filter((t) => !containsTypeParam(t));
7493
+ if (returns.length) this.contextualReturnOf.set(e.func, union(returns));
7494
+ }
7456
7495
  e.func.params.forEach((p, k) => {
7457
7496
  if (p.typeAnnotation || p.pattern || p.default) return;
7458
7497
  const candidates = [];
@@ -7496,7 +7535,9 @@ var TypeAnalyzer = class {
7496
7535
  return property ? [property.type] : o.indexer ? [o.indexer.value] : [];
7497
7536
  });
7498
7537
  if (types.length) {
7499
- this.applyContext(field.type === "TableFieldShorthand" ? field.name : field.value, union(types));
7538
+ const target = field.type === "TableFieldShorthand" ? field.name : field.value;
7539
+ this.contextArms.set(target, types);
7540
+ this.applyContext(target, union(types));
7500
7541
  }
7501
7542
  }
7502
7543
  }
@@ -7557,11 +7598,13 @@ var TypeAnalyzer = class {
7557
7598
  withVarargs(func, body) {
7558
7599
  this.varargs.push(this.varargElement(func));
7559
7600
  this.declaredReturns.push(func.predicate ? booleanType : func.returnType ? this.resolveType(func.returnType) : void 0);
7601
+ this.contextualReturns.push(this.contextualReturnOf.get(func));
7560
7602
  try {
7561
7603
  return body();
7562
7604
  } finally {
7563
7605
  this.varargs.pop();
7564
7606
  this.declaredReturns.pop();
7607
+ this.contextualReturns.pop();
7565
7608
  }
7566
7609
  }
7567
7610
  visitFunctionBodyInner(func, outerEnv) {
@@ -8203,22 +8246,26 @@ var TypeAnalyzer = class {
8203
8246
  if (ids.length < 2) return;
8204
8247
  this.correlateBindings(env, ids, objects.map((member) => names.map((name) => this.propertyType(member, name))));
8205
8248
  }
8206
- /** `(keyType, valueType)` yielded by a generic-for iterator. Handles
8207
- * `ipairs`/`pairs`/`next(t)` and Luau generalized iteration (`for … in t`).
8208
- * `varCount` is how many loop variables were written. */
8249
+ /** `(keyType, valueType, iteratesValues)` yielded by a generic-for
8250
+ * iterator. Handles `ipairs`/`pairs`/`next(t)` and Luau generalized
8251
+ * iteration (`for … in t`). `varCount` is how many loop variables were
8252
+ * written. `iteratesValues` reports the one case where the first variable
8253
+ * is bound to the value rather than the key, which is what lowering has
8254
+ * to know to emit the loop; see `TypeAnalysis.iteratesValues`. */
8209
8255
  iterationTypes(iterNode, iterType, varCount) {
8210
8256
  if (iterNode?.type === "CallExpression" && iterNode.callee.type === "Identifier" && iterNode.arguments[0]) {
8211
8257
  const name = iterNode.callee.name;
8212
8258
  const src = this.expand(this.typeOf.get(iterNode.arguments[0]) ?? unknownType);
8213
- if (name === "ipairs") return [numberType, this.elementType(src, 0)];
8259
+ if (name === "ipairs") return [numberType, this.elementType(src, 0), false];
8214
8260
  if (name === "pairs" || name === "next") {
8215
8261
  if (src.kind === "object") {
8216
8262
  return [
8217
8263
  src.indexer?.key ?? stringType,
8218
- src.indexer?.value ?? union([...src.properties.values()].map((p) => p.type))
8264
+ src.indexer?.value ?? union([...src.properties.values()].map((p) => p.type)),
8265
+ false
8219
8266
  ];
8220
8267
  }
8221
- if (src.kind === "array") return [numberType, src.element];
8268
+ if (src.kind === "array") return [numberType, src.element, false];
8222
8269
  }
8223
8270
  }
8224
8271
  const iterator = this.expand(iterType);
@@ -8226,16 +8273,18 @@ var TypeAnalyzer = class {
8226
8273
  const returns = this.expand(iterator.returns);
8227
8274
  const parts = returns.kind === "tuple" ? returns.elements.map((m) => this.expand(m)) : [returns];
8228
8275
  const at = (i) => parts[i] ?? (parts.length === 1 ? parts[0] : unknownType);
8229
- return [at(0), at(1)];
8276
+ return [at(0), at(1), false];
8230
8277
  }
8231
8278
  const t = this.expand(iterType);
8232
- if (t.kind === "array") return varCount >= 2 ? [numberType, t.element] : [t.element, unknownType];
8279
+ if (t.kind === "array") {
8280
+ return varCount >= 2 ? [numberType, t.element, false] : [t.element, unknownType, true];
8281
+ }
8233
8282
  if (t.kind === "object") {
8234
8283
  const k = t.indexer?.key ?? stringType;
8235
8284
  const v = t.indexer?.value ?? union([...t.properties.values()].map((p) => p.type));
8236
- return varCount >= 2 ? [k, v] : [v, unknownType];
8285
+ return varCount >= 2 ? [k, v, false] : [v, unknownType, true];
8237
8286
  }
8238
- return [unknownType, unknownType];
8287
+ return [unknownType, unknownType, false];
8239
8288
  }
8240
8289
  inferReturnType(body, env) {
8241
8290
  const returns = [];
@@ -8378,6 +8427,7 @@ var TypeAnalyzer = class {
8378
8427
  * resolving, which is what breaks re-entry on a recursive alias. */
8379
8428
  expand(t) {
8380
8429
  if (t.kind !== "genericRef") return t;
8430
+ if (t.origin && t.origin !== this.origin) return t.origin.expand(t);
8381
8431
  const def = this.aliasDefs.get(t.name);
8382
8432
  if (!def) {
8383
8433
  const imported = this.importedTypes.get(t.name);
@@ -8681,7 +8731,7 @@ var TypeAnalyzer = class {
8681
8731
  if (!isAssignable(narrow, declared) && !isAssignable(actual, declared)) {
8682
8732
  this.diagnostics.push({
8683
8733
  node: expr,
8684
- message: `Type '${formatType(actual)}' does not satisfy the expected type '${formatType(declared)}'`
8734
+ message: `Type '${briefType(actual)}' does not satisfy the expected type '${briefType(declared)}'` + this.explainMismatch(actual, declared)
8685
8735
  });
8686
8736
  } else {
8687
8737
  this.reportExcessProperties(expr.expression, declared);
@@ -9060,8 +9110,16 @@ var TypeAnalyzer = class {
9060
9110
  * inferred, so this is a lookup rather than a second pass. */
9061
9111
  widenUnlessAsked(value, at) {
9062
9112
  const wanted = this.expectedTypeOf.get(at);
9113
+ if (value.kind === "literal") {
9114
+ const arms = this.contextArms.get(at);
9115
+ if (arms?.some((arm) => this.admitsLiteral(arm, value.base))) return value;
9116
+ }
9063
9117
  return wanted === void 0 ? widen(value) : this.keepContextualLiterals(value, wanted);
9064
9118
  }
9119
+ /** What each arm of the contract wanted of an expression, unmerged — see
9120
+ * `widenUnlessAsked`. Recorded by `applyTableContext` beside the merged
9121
+ * type it hands to `applyContext`. */
9122
+ contextArms = /* @__PURE__ */ new WeakMap();
9065
9123
  inferObject(expr, env, asConst) {
9066
9124
  const entries = [];
9067
9125
  let indexer;
@@ -9770,8 +9828,9 @@ var TypeAnalyzer = class {
9770
9828
  * themselves are then the whole story. */
9771
9829
  explainMismatch(actual, expected) {
9772
9830
  const from = this.expand(actual);
9773
- const to = this.expand(expected);
9774
- if (from.kind !== "object" || to.kind !== "object") return "";
9831
+ if (from.kind !== "object") return "";
9832
+ const to = this.likeliestArm(from, this.expand(expected));
9833
+ if (to === void 0) return "";
9775
9834
  const missing = [];
9776
9835
  for (const [name, property] of to.properties) {
9777
9836
  if (property.optional || from.properties.has(name) || INTERNAL_MEMBERS.has(name)) continue;
@@ -9796,6 +9855,34 @@ var TypeAnalyzer = class {
9796
9855
  }
9797
9856
  return "";
9798
9857
  }
9858
+ /** Which object of a contract the value was reaching for. One object is
9859
+ * itself; among several, a discriminant decides — the arm whose literal
9860
+ * properties the value already agrees with (`Status: true` picks
9861
+ * `StatSuccess` over `StatError`). Failing that, the arm it is closest to
9862
+ * fitting, so the explanation is about the shortest gap rather than an
9863
+ * arbitrary one. `undefined` when there is no object to explain against. */
9864
+ likeliestArm(from, expected) {
9865
+ const arms = this.membersOf(expected).filter((m) => m.kind === "object");
9866
+ if (arms.length <= 1) return arms[0];
9867
+ const gapOf = (arm) => {
9868
+ let gap = 0;
9869
+ for (const [name, property] of arm.properties) {
9870
+ if (INTERNAL_MEMBERS.has(name)) continue;
9871
+ const own = from.properties.get(name);
9872
+ if (!own) {
9873
+ if (!property.optional) gap += 1;
9874
+ continue;
9875
+ }
9876
+ if (isAssignable(own.type, property.type)) continue;
9877
+ gap += this.expand(property.type).kind === "literal" ? 100 : 1;
9878
+ }
9879
+ for (const name of from.properties.keys()) {
9880
+ if (!INTERNAL_MEMBERS.has(name) && !arm.properties.has(name) && !arm.indexer) gap += 1;
9881
+ }
9882
+ return gap;
9883
+ };
9884
+ return arms.reduce((best, arm) => gapOf(arm) < gapOf(best) ? arm : best);
9885
+ }
9799
9886
  bindingIdOf(id) {
9800
9887
  return this.scopes.bindingOf.get(id);
9801
9888
  }
@@ -9842,7 +9929,15 @@ function briefType(t) {
9842
9929
  const shown = t.types.slice(0, 6).map(formatType).join(" | ");
9843
9930
  return `${shown} | ... ${t.types.length - 6} more`;
9844
9931
  }
9845
- return formatType(t);
9932
+ const full = formatType(t);
9933
+ if (full.length <= MAX_TYPE) return full;
9934
+ if (t.kind === "object" && t.properties.size) {
9935
+ const names = [...t.properties.keys()].filter((n) => !INTERNAL_MEMBERS.has(n));
9936
+ const shown = names.slice(0, MAX_MISSING);
9937
+ const rest = names.length - shown.length;
9938
+ return `{ ${shown.join(", ")}${rest > 0 ? `, ... ${rest} more` : ""} }`;
9939
+ }
9940
+ return `${full.slice(0, MAX_TYPE)}...`;
9846
9941
  }
9847
9942
 
9848
9943
  // src/project/host.ts
package/dist/index.d.cts CHANGED
@@ -1223,6 +1223,15 @@ interface GenericRefType {
1223
1223
  kind: "genericRef";
1224
1224
  name: string;
1225
1225
  typeArguments: Type[];
1226
+ /** The module whose alias this names. A recursive alias is left as a ref
1227
+ * inside its own structure, and that ref travels with the type into every
1228
+ * module that imports it — where `name` may mean nothing, or a different
1229
+ * type. Expanding through `origin` reads the name where it was written. */
1230
+ origin?: TypeOrigin;
1231
+ }
1232
+ /** A module's own alias resolution, handed out on the refs it creates. */
1233
+ interface TypeOrigin {
1234
+ expand(t: GenericRefType): Type;
1226
1235
  }
1227
1236
  /** `keyof T`. */
1228
1237
  interface KeyofType {
@@ -1405,6 +1414,13 @@ interface TypeAnalysis {
1405
1414
  /** Top-level type aliases, resolved — and the type names this module
1406
1415
  * imports, so tooling treats both alike. */
1407
1416
  readonly aliases: Map<string, Type>;
1417
+ /** The `for x in t` loops that walk a table directly, where tilua's one
1418
+ * variable takes the *value* — not an iterator such as `pairs(t)` or
1419
+ * `string.gmatch(s, p)`, whose variables are bound as written. Luau hands
1420
+ * the key over first, so lowering these needs a key variable in front.
1421
+ * Deciding that here keeps it next to the types the same choice produces:
1422
+ * the variable's type and the code bound to it cannot drift apart. */
1423
+ readonly iteratesValues: ReadonlySet<GenericForStatement>;
1408
1424
  readonly diagnostics: TypeDiagnostic[];
1409
1425
  }
1410
1426
  /** A type a module exports: the resolved type, plus the parameter names of a
@@ -1672,4 +1688,4 @@ declare const tilua: {
1672
1688
  readonly analyzeTypes: typeof analyzeTypes;
1673
1689
  };
1674
1690
 
1675
- export { type AnalyzeTypesOptions, type AnyType, type ArrayExpression, type ArrayPattern, type ArrayPatternElement, type ArrayType, type ArrayTypeNode, type AsConstExpression, type AssignmentStatement, type BaseNode, type BaseToken, type BinaryExpression, BinaryOperators, type Binding, type BindingId, type BindingKind, type BindingTarget, type Block, type BooleanLiteral, type BreakStatement, type BuildTarget, CONFIG_FILE_NAMES, type CallExpression, type CallStatement, type ClassAccessor, type ClassConstructor, type ClassDeclaration, type ClassExpression, type ClassField, type ClassInfo, type ClassLike, type ClassMember, type ClassMethod, type CompoundAssignmentStatement, type ConditionalType, type ConditionalTypeNode, type ConfigLookup, type ConfigProblem, type ContinueStatement, type DeclareClassStatement, type DeclareStatement, type DifferenceType, type DifferenceTypeNode, type Directive, type DirectiveKind, type DirectiveOutcome, type Directives, type DoStatement, type EOFToken, type ErrorExpression, type ErrorStatement, type ExportAllStatement, type ExportDefaultStatement, type ExportNamedStatement, type ExportSpecifier, type ExportStatement, type ExportTypeAliasStatement, type ExportedType, type Expression, type ExpressionStatement, type FunctionBody, type FunctionDeclaration, type FunctionDeclarationStatement, type FunctionExpression, type FunctionName, type FunctionParam, type FunctionParameter, type FunctionSignature, type FunctionType, type FunctionTypeNode, type FunctionTypeParameter, type GenericForStatement, type GenericRefType, type GenericTypeParameter, type Identifier, type IdentifierPattern, type IdentifierToken, type IfClause, type IfElseExpression, type IfStatement, type ImportSpecifier, type ImportStatement, type IndexExpression, type IndexedAccessType, type IndexedAccessTypeNode, type InferType, type InferTypeNode, type InterpolatedStringExpression, type InterpolatedStringPart, type InterpolatedStringPart_Expression, type InterpolatedStringPart_String, type InterpolatedStringToken, type IntersectionType, type IntersectionTypeNode, type KeyofType, type KeyofTypeNode, type KeywordToken, Keywords, LexError, type LiteralToken, type LiteralType, type LoweringModule, type LoweringPlugin, type MappedType, type MappedTypeNode, type MemberExpression, type MethodCall, type MethodCallExpression, type MethodLowering, type ModuleExports, type NeverType, type NewExpression, type NilLiteral, type Node, type NumberLiteral, type NumericForStatement, type ObjectPattern, type ObjectPatternProperty, type ObjectProperty, type ObjectType, type OperatorToken, Operators, PRELUDE_SOURCE, type ParenthesizedExpression, type ParenthesizedTypeNode, ParseError, type ParserOptions, type PrimitiveName, type PrimitiveType, type Program, type ProjectHost, type PunctuatorToken, Punctuators, type RecoverResult, type RepeatStatement, type ReturnStatement, type SatisfiesExpression, type ScopeAnalysis, type ScopeDiagnostic, type SourceComment, type SourceMapNode, type SourceMapOptions, type SourceMapTypes, type SpreadElement, type Statement, type StringLiteral, type SuperExpression, type TableExpression, type TableField, type TableTypeNode, type TableTypeProperty, type TemplateLiteralType, type TemplateLiteralTypeNode, type TiluaConfig, type Token, type TokenizeOptions, type TupleType, type TupleTypeNode, type Type, type TypeAliasStatement, type TypeAnalysis, type TypeAssertionExpression, type TypeDiagnostic, type TypeLibraries, type TypeLiteralBoolean, type TypeLiteralNumber, type TypeLiteralString, type TypeNode, type TypePackNode, type TypeParamType, type TypePredicate, type TypePredicateNode, type TypeReference, type TypedIdentifier, type TypeofTypeNode, UNUSED_EXPECT_ERROR, type UnaryExpression, UnaryOperators, type UnionType, type UnionTypeNode, type UnknownType, type VarargExpression, type VariableDeclaration, type VariadicTypeNode, type WhileStatement, aliasNameOf, analyzeScopes, analyzeTypes, anyType, applyDirectives, arrayOf, booleanType, bufferType, containsTypeParam, declaredUnknownType, tilua as default, difference, directivesOf, equalTypes, falsyType, findConfig, fn, formatType, getBinding, intersection, isAssignable, isClassType, isGlobal, isPossiblyFalsy, isPossiblyTruthy, isUnassignedGlobal, literal, loadConfig, matchInfer, moduleCandidates, moduleExports, narrowExclude, narrowFalsy, narrowTo, narrowTruthy, neverType, nilType, nodeHost, numberType, objectType, optional, overlaps, parse, parseExpressionFromSource, parseTokens, parseWithRecovery, primitive, readDirectives, resolveModulePath, resolveTypeLibraries, setAliasExpander, setDeferredBound, sourceMapTypes, stringType, stripJsonComments, substitute, templateMatches, threadType, tilua, tokenize, tuple, typeParam, unify, union, unknownType, widen, withAliasName, withoutAliasName };
1691
+ export { type AnalyzeTypesOptions, type AnyType, type ArrayExpression, type ArrayPattern, type ArrayPatternElement, type ArrayType, type ArrayTypeNode, type AsConstExpression, type AssignmentStatement, type BaseNode, type BaseToken, type BinaryExpression, BinaryOperators, type Binding, type BindingId, type BindingKind, type BindingTarget, type Block, type BooleanLiteral, type BreakStatement, type BuildTarget, CONFIG_FILE_NAMES, type CallExpression, type CallStatement, type ClassAccessor, type ClassConstructor, type ClassDeclaration, type ClassExpression, type ClassField, type ClassInfo, type ClassLike, type ClassMember, type ClassMethod, type CompoundAssignmentStatement, type ConditionalType, type ConditionalTypeNode, type ConfigLookup, type ConfigProblem, type ContinueStatement, type DeclareClassStatement, type DeclareStatement, type DifferenceType, type DifferenceTypeNode, type Directive, type DirectiveKind, type DirectiveOutcome, type Directives, type DoStatement, type EOFToken, type ErrorExpression, type ErrorStatement, type ExportAllStatement, type ExportDefaultStatement, type ExportNamedStatement, type ExportSpecifier, type ExportStatement, type ExportTypeAliasStatement, type ExportedType, type Expression, type ExpressionStatement, type FunctionBody, type FunctionDeclaration, type FunctionDeclarationStatement, type FunctionExpression, type FunctionName, type FunctionParam, type FunctionParameter, type FunctionSignature, type FunctionType, type FunctionTypeNode, type FunctionTypeParameter, type GenericForStatement, type GenericRefType, type GenericTypeParameter, type Identifier, type IdentifierPattern, type IdentifierToken, type IfClause, type IfElseExpression, type IfStatement, type ImportSpecifier, type ImportStatement, type IndexExpression, type IndexedAccessType, type IndexedAccessTypeNode, type InferType, type InferTypeNode, type InterpolatedStringExpression, type InterpolatedStringPart, type InterpolatedStringPart_Expression, type InterpolatedStringPart_String, type InterpolatedStringToken, type IntersectionType, type IntersectionTypeNode, type KeyofType, type KeyofTypeNode, type KeywordToken, Keywords, LexError, type LiteralToken, type LiteralType, type LoweringModule, type LoweringPlugin, type MappedType, type MappedTypeNode, type MemberExpression, type MethodCall, type MethodCallExpression, type MethodLowering, type ModuleExports, type NeverType, type NewExpression, type NilLiteral, type Node, type NumberLiteral, type NumericForStatement, type ObjectPattern, type ObjectPatternProperty, type ObjectProperty, type ObjectType, type OperatorToken, Operators, PRELUDE_SOURCE, type ParenthesizedExpression, type ParenthesizedTypeNode, ParseError, type ParserOptions, type PrimitiveName, type PrimitiveType, type Program, type ProjectHost, type PunctuatorToken, Punctuators, type RecoverResult, type RepeatStatement, type ReturnStatement, type SatisfiesExpression, type ScopeAnalysis, type ScopeDiagnostic, type SourceComment, type SourceMapNode, type SourceMapOptions, type SourceMapTypes, type SpreadElement, type Statement, type StringLiteral, type SuperExpression, type TableExpression, type TableField, type TableTypeNode, type TableTypeProperty, type TemplateLiteralType, type TemplateLiteralTypeNode, type TiluaConfig, type Token, type TokenizeOptions, type TupleType, type TupleTypeNode, type Type, type TypeAliasStatement, type TypeAnalysis, type TypeAssertionExpression, type TypeDiagnostic, type TypeLibraries, type TypeLiteralBoolean, type TypeLiteralNumber, type TypeLiteralString, type TypeNode, type TypeOrigin, type TypePackNode, type TypeParamType, type TypePredicate, type TypePredicateNode, type TypeReference, type TypedIdentifier, type TypeofTypeNode, UNUSED_EXPECT_ERROR, type UnaryExpression, UnaryOperators, type UnionType, type UnionTypeNode, type UnknownType, type VarargExpression, type VariableDeclaration, type VariadicTypeNode, type WhileStatement, aliasNameOf, analyzeScopes, analyzeTypes, anyType, applyDirectives, arrayOf, booleanType, bufferType, containsTypeParam, declaredUnknownType, tilua as default, difference, directivesOf, equalTypes, falsyType, findConfig, fn, formatType, getBinding, intersection, isAssignable, isClassType, isGlobal, isPossiblyFalsy, isPossiblyTruthy, isUnassignedGlobal, literal, loadConfig, matchInfer, moduleCandidates, moduleExports, narrowExclude, narrowFalsy, narrowTo, narrowTruthy, neverType, nilType, nodeHost, numberType, objectType, optional, overlaps, parse, parseExpressionFromSource, parseTokens, parseWithRecovery, primitive, readDirectives, resolveModulePath, resolveTypeLibraries, setAliasExpander, setDeferredBound, sourceMapTypes, stringType, stripJsonComments, substitute, templateMatches, threadType, tilua, tokenize, tuple, typeParam, unify, union, unknownType, widen, withAliasName, withoutAliasName };
package/dist/index.d.ts CHANGED
@@ -1223,6 +1223,15 @@ interface GenericRefType {
1223
1223
  kind: "genericRef";
1224
1224
  name: string;
1225
1225
  typeArguments: Type[];
1226
+ /** The module whose alias this names. A recursive alias is left as a ref
1227
+ * inside its own structure, and that ref travels with the type into every
1228
+ * module that imports it — where `name` may mean nothing, or a different
1229
+ * type. Expanding through `origin` reads the name where it was written. */
1230
+ origin?: TypeOrigin;
1231
+ }
1232
+ /** A module's own alias resolution, handed out on the refs it creates. */
1233
+ interface TypeOrigin {
1234
+ expand(t: GenericRefType): Type;
1226
1235
  }
1227
1236
  /** `keyof T`. */
1228
1237
  interface KeyofType {
@@ -1405,6 +1414,13 @@ interface TypeAnalysis {
1405
1414
  /** Top-level type aliases, resolved — and the type names this module
1406
1415
  * imports, so tooling treats both alike. */
1407
1416
  readonly aliases: Map<string, Type>;
1417
+ /** The `for x in t` loops that walk a table directly, where tilua's one
1418
+ * variable takes the *value* — not an iterator such as `pairs(t)` or
1419
+ * `string.gmatch(s, p)`, whose variables are bound as written. Luau hands
1420
+ * the key over first, so lowering these needs a key variable in front.
1421
+ * Deciding that here keeps it next to the types the same choice produces:
1422
+ * the variable's type and the code bound to it cannot drift apart. */
1423
+ readonly iteratesValues: ReadonlySet<GenericForStatement>;
1408
1424
  readonly diagnostics: TypeDiagnostic[];
1409
1425
  }
1410
1426
  /** A type a module exports: the resolved type, plus the parameter names of a
@@ -1672,4 +1688,4 @@ declare const tilua: {
1672
1688
  readonly analyzeTypes: typeof analyzeTypes;
1673
1689
  };
1674
1690
 
1675
- export { type AnalyzeTypesOptions, type AnyType, type ArrayExpression, type ArrayPattern, type ArrayPatternElement, type ArrayType, type ArrayTypeNode, type AsConstExpression, type AssignmentStatement, type BaseNode, type BaseToken, type BinaryExpression, BinaryOperators, type Binding, type BindingId, type BindingKind, type BindingTarget, type Block, type BooleanLiteral, type BreakStatement, type BuildTarget, CONFIG_FILE_NAMES, type CallExpression, type CallStatement, type ClassAccessor, type ClassConstructor, type ClassDeclaration, type ClassExpression, type ClassField, type ClassInfo, type ClassLike, type ClassMember, type ClassMethod, type CompoundAssignmentStatement, type ConditionalType, type ConditionalTypeNode, type ConfigLookup, type ConfigProblem, type ContinueStatement, type DeclareClassStatement, type DeclareStatement, type DifferenceType, type DifferenceTypeNode, type Directive, type DirectiveKind, type DirectiveOutcome, type Directives, type DoStatement, type EOFToken, type ErrorExpression, type ErrorStatement, type ExportAllStatement, type ExportDefaultStatement, type ExportNamedStatement, type ExportSpecifier, type ExportStatement, type ExportTypeAliasStatement, type ExportedType, type Expression, type ExpressionStatement, type FunctionBody, type FunctionDeclaration, type FunctionDeclarationStatement, type FunctionExpression, type FunctionName, type FunctionParam, type FunctionParameter, type FunctionSignature, type FunctionType, type FunctionTypeNode, type FunctionTypeParameter, type GenericForStatement, type GenericRefType, type GenericTypeParameter, type Identifier, type IdentifierPattern, type IdentifierToken, type IfClause, type IfElseExpression, type IfStatement, type ImportSpecifier, type ImportStatement, type IndexExpression, type IndexedAccessType, type IndexedAccessTypeNode, type InferType, type InferTypeNode, type InterpolatedStringExpression, type InterpolatedStringPart, type InterpolatedStringPart_Expression, type InterpolatedStringPart_String, type InterpolatedStringToken, type IntersectionType, type IntersectionTypeNode, type KeyofType, type KeyofTypeNode, type KeywordToken, Keywords, LexError, type LiteralToken, type LiteralType, type LoweringModule, type LoweringPlugin, type MappedType, type MappedTypeNode, type MemberExpression, type MethodCall, type MethodCallExpression, type MethodLowering, type ModuleExports, type NeverType, type NewExpression, type NilLiteral, type Node, type NumberLiteral, type NumericForStatement, type ObjectPattern, type ObjectPatternProperty, type ObjectProperty, type ObjectType, type OperatorToken, Operators, PRELUDE_SOURCE, type ParenthesizedExpression, type ParenthesizedTypeNode, ParseError, type ParserOptions, type PrimitiveName, type PrimitiveType, type Program, type ProjectHost, type PunctuatorToken, Punctuators, type RecoverResult, type RepeatStatement, type ReturnStatement, type SatisfiesExpression, type ScopeAnalysis, type ScopeDiagnostic, type SourceComment, type SourceMapNode, type SourceMapOptions, type SourceMapTypes, type SpreadElement, type Statement, type StringLiteral, type SuperExpression, type TableExpression, type TableField, type TableTypeNode, type TableTypeProperty, type TemplateLiteralType, type TemplateLiteralTypeNode, type TiluaConfig, type Token, type TokenizeOptions, type TupleType, type TupleTypeNode, type Type, type TypeAliasStatement, type TypeAnalysis, type TypeAssertionExpression, type TypeDiagnostic, type TypeLibraries, type TypeLiteralBoolean, type TypeLiteralNumber, type TypeLiteralString, type TypeNode, type TypePackNode, type TypeParamType, type TypePredicate, type TypePredicateNode, type TypeReference, type TypedIdentifier, type TypeofTypeNode, UNUSED_EXPECT_ERROR, type UnaryExpression, UnaryOperators, type UnionType, type UnionTypeNode, type UnknownType, type VarargExpression, type VariableDeclaration, type VariadicTypeNode, type WhileStatement, aliasNameOf, analyzeScopes, analyzeTypes, anyType, applyDirectives, arrayOf, booleanType, bufferType, containsTypeParam, declaredUnknownType, tilua as default, difference, directivesOf, equalTypes, falsyType, findConfig, fn, formatType, getBinding, intersection, isAssignable, isClassType, isGlobal, isPossiblyFalsy, isPossiblyTruthy, isUnassignedGlobal, literal, loadConfig, matchInfer, moduleCandidates, moduleExports, narrowExclude, narrowFalsy, narrowTo, narrowTruthy, neverType, nilType, nodeHost, numberType, objectType, optional, overlaps, parse, parseExpressionFromSource, parseTokens, parseWithRecovery, primitive, readDirectives, resolveModulePath, resolveTypeLibraries, setAliasExpander, setDeferredBound, sourceMapTypes, stringType, stripJsonComments, substitute, templateMatches, threadType, tilua, tokenize, tuple, typeParam, unify, union, unknownType, widen, withAliasName, withoutAliasName };
1691
+ export { type AnalyzeTypesOptions, type AnyType, type ArrayExpression, type ArrayPattern, type ArrayPatternElement, type ArrayType, type ArrayTypeNode, type AsConstExpression, type AssignmentStatement, type BaseNode, type BaseToken, type BinaryExpression, BinaryOperators, type Binding, type BindingId, type BindingKind, type BindingTarget, type Block, type BooleanLiteral, type BreakStatement, type BuildTarget, CONFIG_FILE_NAMES, type CallExpression, type CallStatement, type ClassAccessor, type ClassConstructor, type ClassDeclaration, type ClassExpression, type ClassField, type ClassInfo, type ClassLike, type ClassMember, type ClassMethod, type CompoundAssignmentStatement, type ConditionalType, type ConditionalTypeNode, type ConfigLookup, type ConfigProblem, type ContinueStatement, type DeclareClassStatement, type DeclareStatement, type DifferenceType, type DifferenceTypeNode, type Directive, type DirectiveKind, type DirectiveOutcome, type Directives, type DoStatement, type EOFToken, type ErrorExpression, type ErrorStatement, type ExportAllStatement, type ExportDefaultStatement, type ExportNamedStatement, type ExportSpecifier, type ExportStatement, type ExportTypeAliasStatement, type ExportedType, type Expression, type ExpressionStatement, type FunctionBody, type FunctionDeclaration, type FunctionDeclarationStatement, type FunctionExpression, type FunctionName, type FunctionParam, type FunctionParameter, type FunctionSignature, type FunctionType, type FunctionTypeNode, type FunctionTypeParameter, type GenericForStatement, type GenericRefType, type GenericTypeParameter, type Identifier, type IdentifierPattern, type IdentifierToken, type IfClause, type IfElseExpression, type IfStatement, type ImportSpecifier, type ImportStatement, type IndexExpression, type IndexedAccessType, type IndexedAccessTypeNode, type InferType, type InferTypeNode, type InterpolatedStringExpression, type InterpolatedStringPart, type InterpolatedStringPart_Expression, type InterpolatedStringPart_String, type InterpolatedStringToken, type IntersectionType, type IntersectionTypeNode, type KeyofType, type KeyofTypeNode, type KeywordToken, Keywords, LexError, type LiteralToken, type LiteralType, type LoweringModule, type LoweringPlugin, type MappedType, type MappedTypeNode, type MemberExpression, type MethodCall, type MethodCallExpression, type MethodLowering, type ModuleExports, type NeverType, type NewExpression, type NilLiteral, type Node, type NumberLiteral, type NumericForStatement, type ObjectPattern, type ObjectPatternProperty, type ObjectProperty, type ObjectType, type OperatorToken, Operators, PRELUDE_SOURCE, type ParenthesizedExpression, type ParenthesizedTypeNode, ParseError, type ParserOptions, type PrimitiveName, type PrimitiveType, type Program, type ProjectHost, type PunctuatorToken, Punctuators, type RecoverResult, type RepeatStatement, type ReturnStatement, type SatisfiesExpression, type ScopeAnalysis, type ScopeDiagnostic, type SourceComment, type SourceMapNode, type SourceMapOptions, type SourceMapTypes, type SpreadElement, type Statement, type StringLiteral, type SuperExpression, type TableExpression, type TableField, type TableTypeNode, type TableTypeProperty, type TemplateLiteralType, type TemplateLiteralTypeNode, type TiluaConfig, type Token, type TokenizeOptions, type TupleType, type TupleTypeNode, type Type, type TypeAliasStatement, type TypeAnalysis, type TypeAssertionExpression, type TypeDiagnostic, type TypeLibraries, type TypeLiteralBoolean, type TypeLiteralNumber, type TypeLiteralString, type TypeNode, type TypeOrigin, type TypePackNode, type TypeParamType, type TypePredicate, type TypePredicateNode, type TypeReference, type TypedIdentifier, type TypeofTypeNode, UNUSED_EXPECT_ERROR, type UnaryExpression, UnaryOperators, type UnionType, type UnionTypeNode, type UnknownType, type VarargExpression, type VariableDeclaration, type VariadicTypeNode, type WhileStatement, aliasNameOf, analyzeScopes, analyzeTypes, anyType, applyDirectives, arrayOf, booleanType, bufferType, containsTypeParam, declaredUnknownType, tilua as default, difference, directivesOf, equalTypes, falsyType, findConfig, fn, formatType, getBinding, intersection, isAssignable, isClassType, isGlobal, isPossiblyFalsy, isPossiblyTruthy, isUnassignedGlobal, literal, loadConfig, matchInfer, moduleCandidates, moduleExports, narrowExclude, narrowFalsy, narrowTo, narrowTruthy, neverType, nilType, nodeHost, numberType, objectType, optional, overlaps, parse, parseExpressionFromSource, parseTokens, parseWithRecovery, primitive, readDirectives, resolveModulePath, resolveTypeLibraries, setAliasExpander, setDeferredBound, sourceMapTypes, stringType, stripJsonComments, substitute, templateMatches, threadType, tilua, tokenize, tuple, typeParam, unify, union, unknownType, widen, withAliasName, withoutAliasName };