@tilua/parser 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -4670,14 +4670,17 @@ function classArguments(t, name) {
4670
4670
  if (t.kind === "object") return t.class?.typeArguments?.get(name);
4671
4671
  return void 0;
4672
4672
  }
4673
- function unify(param, arg, vars, out) {
4673
+ function unify(param, arg, vars, out, how = "union") {
4674
4674
  if (param.kind === "typeParam" && param.constraint && !vars.has(param.name)) {
4675
- unify(param.constraint, arg, vars, out);
4675
+ unify(param.constraint, arg, vars, out, how);
4676
4676
  return;
4677
4677
  }
4678
4678
  if (param.kind === "typeParam" && vars.has(param.name)) {
4679
4679
  const prev = out.get(param.name);
4680
- out.set(param.name, prev ? union([prev, arg]) : arg);
4680
+ if (!prev) out.set(param.name, arg);
4681
+ else if (isAssignable(arg, prev)) {
4682
+ } else if (isAssignable(prev, arg)) out.set(param.name, arg);
4683
+ else if (how === "union") out.set(param.name, union([prev, arg]));
4681
4684
  return;
4682
4685
  }
4683
4686
  if (arg.kind === "any" || arg.kind === "never") return;
@@ -7862,8 +7865,10 @@ var TypeAnalyzer = class {
7862
7865
  // --------------------------------------------------------
7863
7866
  // Functions
7864
7867
  // --------------------------------------------------------
7865
- visitFunctionBody(func, outerEnv) {
7866
- this.withTypeParams(func.generics, () => this.visitFunctionBodyInner(func, outerEnv));
7868
+ /** `returns`, when given, collects the type of each `return` the walk
7869
+ * reads — see `inferFunctionBody`. */
7870
+ visitFunctionBody(func, outerEnv, returns) {
7871
+ this.withTypeParams(func.generics, () => this.visitFunctionBodyInner(func, outerEnv, returns));
7867
7872
  }
7868
7873
  /** A parameter's type: annotation, else a shape synthesized from a
7869
7874
  * destructuring pattern, else inferred from its default, else `any`. */
@@ -7912,6 +7917,53 @@ var TypeAnalyzer = class {
7912
7917
  * it, as in TypeScript: `signal:Connect(function(player) ... end)` knows
7913
7918
  * `player` from `Connect`'s callback type. Anything else is inferred as
7914
7919
  * usual. */
7920
+ /** The arguments of a call, in two passes where one is needed.
7921
+ *
7922
+ * A function written at the call site with a parameter nothing annotates
7923
+ * reads that parameter from the signature — and where the signature says
7924
+ * `(v: T) => U`, `T` is only known once the other arguments have been
7925
+ * read. So such an argument is read once quietly, to get a shape to pick
7926
+ * a signature with, and then again with `T` in hand: `map(xs, v => v + 1)`
7927
+ * has its `v` a number by then, and `U` follows from what the body
7928
+ * answers. Everything else is read once, as it always was. */
7929
+ inferArguments(written, fns, selfOf, extra, env) {
7930
+ const expected = this.expectedArguments(written, fns, selfOf);
7931
+ written.forEach((a, i) => this.applyContext(a, expected[i]));
7932
+ const waits = written.map((a, i) => this.waitsOnInference(a, expected[i]));
7933
+ if (!waits.some(Boolean)) return written.map((a) => this.infer(a, env));
7934
+ const argTypes = written.map((a, i) => waits[i] ? this.quietly(() => this.infer(a, env)) : this.infer(a, env));
7935
+ const picked = this.pickOverload(fns, argTypes, (f) => extra(f, argTypes), this.spreadOf(written, selfOf(fns[0])));
7936
+ const subst = picked?.typeParams?.length ? this.inferTypeArgs(picked, extra(picked, argTypes)) : void 0;
7937
+ written.forEach((a, i) => {
7938
+ if (!waits[i]) return;
7939
+ if (picked && subst) {
7940
+ const self = selfOf(picked);
7941
+ const declared = i + self < picked.params.length ? picked.params[i + self].type : picked.varargs;
7942
+ if (declared) this.applyContext(a, this.reduceType(substitute(declared, subst)));
7943
+ }
7944
+ argTypes[i] = this.infer(a, env);
7945
+ });
7946
+ return argTypes;
7947
+ }
7948
+ /** Is this argument a function whose own type waits on the call's? */
7949
+ waitsOnInference(arg, expected) {
7950
+ if (!expected || !containsTypeParam(expected)) return false;
7951
+ let e = arg;
7952
+ while (e.type === "ParenthesizedExpression") e = e.expression;
7953
+ if (e.type !== "FunctionExpression") return false;
7954
+ return e.func.params.some((p) => !p.typeAnnotation && !p.default && !p.pattern && p.name !== "self" && p.name !== "this");
7955
+ }
7956
+ /** Read something without saying anything about it: a first pass whose
7957
+ * only purpose is a shape to go on. */
7958
+ quietly(read) {
7959
+ const was = this.emitDiagnostics;
7960
+ this.emitDiagnostics = false;
7961
+ try {
7962
+ return read();
7963
+ } finally {
7964
+ this.emitDiagnostics = was;
7965
+ }
7966
+ }
7915
7967
  applyContext(expr, expected) {
7916
7968
  let e = expr;
7917
7969
  while (e.type === "ParenthesizedExpression") e = e.expression;
@@ -8060,7 +8112,7 @@ var TypeAnalyzer = class {
8060
8112
  this.contextualReturns.pop();
8061
8113
  }
8062
8114
  }
8063
- visitFunctionBodyInner(func, outerEnv) {
8115
+ visitFunctionBodyInner(func, outerEnv, returns) {
8064
8116
  const env = forkEnv(outerEnv);
8065
8117
  for (const p of func.params) {
8066
8118
  if (p.pattern) {
@@ -8077,7 +8129,7 @@ var TypeAnalyzer = class {
8077
8129
  if (p.typeAnnotation) this.annotated.add(id);
8078
8130
  }
8079
8131
  }
8080
- this.withVarargs(func, () => this.collectReturns(void 0, () => {
8132
+ this.withVarargs(func, () => this.collectReturns(returns, () => {
8081
8133
  this.visitBlock(func.body, env);
8082
8134
  this.checkReturnsAtAll(func, this.declaredReturns[this.declaredReturns.length - 1]);
8083
8135
  }));
@@ -8131,7 +8183,7 @@ var TypeAnalyzer = class {
8131
8183
  if (arg === void 0) return;
8132
8184
  const param = p.type.kind === "typeParam" && p.type.constraint ? { ...p.type, constraint: this.reduceType(p.type.constraint) } : p.type;
8133
8185
  const preserve = keepsLiterals(param) || param.kind !== "typeParam" && containsTypeParam(param);
8134
- unify(p.type, preserve ? arg : widen(arg), vars, subst);
8186
+ unify(p.type, preserve ? arg : widen(arg), vars, subst, "first");
8135
8187
  });
8136
8188
  if (f.varargs && f.restIsWhole) {
8137
8189
  const rest = argTypes.slice(f.params.length).map((a) => a === void 0 ? unknownType : widen(a));
@@ -8482,7 +8534,12 @@ var TypeAnalyzer = class {
8482
8534
  asserts: node.asserts
8483
8535
  };
8484
8536
  }
8485
- inferFunctionBody(func, env) {
8537
+ /** `visited`, when given, is what the real walk of the body just
8538
+ * collected from its `return`s: a function expression is walked before
8539
+ * its type is asked for, so there is nothing left to guess, and walking
8540
+ * the body a second time only to read them made every callback nested in
8541
+ * another cost twice its parent's. */
8542
+ inferFunctionBody(func, env, visited) {
8486
8543
  const names = func.generics.map((g) => g.name);
8487
8544
  return this.withTypeParams(func.generics, () => {
8488
8545
  const params = func.params.flatMap((p) => {
@@ -8511,6 +8568,8 @@ var TypeAnalyzer = class {
8511
8568
  returns = this.resolveType(func.returnType);
8512
8569
  } else if (func.predicate) {
8513
8570
  returns = booleanType;
8571
+ } else if (visited) {
8572
+ returns = visited.length ? union([...visited]) : this.withVarargs(func, () => this.silently(() => this.inferReturnType(func.body, bodyEnv)));
8514
8573
  } else {
8515
8574
  const collected = [];
8516
8575
  returns = this.withVarargs(func, () => this.silently(() => {
@@ -9383,10 +9442,12 @@ var TypeAnalyzer = class {
9383
9442
  return this.inferArray(expr, env, false);
9384
9443
  case "TableExpression":
9385
9444
  return this.inferObject(expr, env, false);
9386
- case "FunctionExpression":
9445
+ case "FunctionExpression": {
9387
9446
  this.checkParamOrder(expr.func.params, expr);
9388
- this.visitFunctionBody(expr.func, env);
9389
- return this.inferFunctionBody(expr.func, env);
9447
+ const returned = [];
9448
+ this.visitFunctionBody(expr.func, env, returned);
9449
+ return this.inferFunctionBody(expr.func, env, returned);
9450
+ }
9390
9451
  case "ParenthesizedExpression":
9391
9452
  return this.infer(expr.expression, env);
9392
9453
  case "TypeAssertionExpression": {
@@ -9590,9 +9651,7 @@ var TypeAnalyzer = class {
9590
9651
  const united = this.unionSignatures(callee);
9591
9652
  const fns = united ?? this.overloadsOf(callee);
9592
9653
  const explicit = this.explicitTypeArguments(expr, fns);
9593
- const expected = this.expectedArguments(expr.arguments, fns, () => 0);
9594
- expr.arguments.forEach((a, i) => this.applyContext(a, expected[i]));
9595
- const argTypes = expr.arguments.map((a) => this.infer(a, env));
9654
+ const argTypes = this.inferArguments(expr.arguments, fns, () => 0, (_, args) => args, env);
9596
9655
  if (fns.length) {
9597
9656
  this.recordExpected(expr.arguments, fns, () => 0, () => argTypes);
9598
9657
  const spread = this.spreadOf(expr.arguments);
@@ -9657,9 +9716,13 @@ var TypeAnalyzer = class {
9657
9716
  const united = this.unionSignatures(method);
9658
9717
  const fns = united ?? this.overloadsOf(method);
9659
9718
  const explicit = this.explicitTypeArguments(expr, fns);
9660
- const expected = this.expectedArguments(expr.arguments, fns, (f) => this.takesSelf(f) ? 1 : 0);
9661
- expr.arguments.forEach((a, i) => this.applyContext(a, expected[i]));
9662
- const argTypes = expr.arguments.map((a) => this.infer(a, env));
9719
+ const argTypes = this.inferArguments(
9720
+ expr.arguments,
9721
+ fns,
9722
+ (f) => this.takesSelf(f) ? 1 : 0,
9723
+ (f, args) => this.takesSelf(f) ? [objType, ...args] : args,
9724
+ env
9725
+ );
9663
9726
  if (fns.length) {
9664
9727
  const withSelf = (f) => this.takesSelf(f) ? [objType, ...argTypes] : argTypes;
9665
9728
  const selfOf = (f) => this.takesSelf(f) ? 1 : 0;
package/dist/index.d.cts CHANGED
@@ -1377,7 +1377,15 @@ declare function tupleMembers(t: TupleType): Type[];
1377
1377
  declare function objectType(entries: Iterable<[string, ObjectProperty]>, indexer?: ObjectType["indexer"], frozen?: boolean): ObjectType;
1378
1378
  declare function fn(params: FunctionParam[], returns: Type, varargs?: Type, typeParams?: string[], predicate?: TypePredicate): FunctionType;
1379
1379
  declare function substitute(t: Type, subst: Map<string, Type>): Type;
1380
- declare function unify(param: Type, arg: Type, vars: Set<string>, out: Map<string, Type>): void;
1380
+ /** How a type parameter takes a second candidate, at the top of a
1381
+ * parameter. Below it — a list's elements, a tuple's places — every
1382
+ * candidate is the same site and they gather, whichever mode was asked for. Arguments collected by
1383
+ * one `...rest: T[]` are all of them equally, so `firstOf(1, "a")` reads
1384
+ * `T` as their union. Two parameters written separately are not: the one
1385
+ * written first says what `T` is, and an argument that disagrees with it is
1386
+ * a mistake to report rather than a reason to widen. */
1387
+ type Unification = "union" | "first";
1388
+ declare function unify(param: Type, arg: Type, vars: Set<string>, out: Map<string, Type>, how?: Unification): void;
1381
1389
  declare function union(types: Type[]): Type;
1382
1390
  declare function intersection(types: Type[]): Type;
1383
1391
  /** `base - excluded`, simplified as far as the base allows. */
@@ -1818,4 +1826,4 @@ declare const tilua: {
1818
1826
  readonly analyzeTypes: typeof analyzeTypes;
1819
1827
  };
1820
1828
 
1821
- export { type AnalyzeTypesOptions, type AnyType, type ArgumentInfo, 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 CallLowering, type CallSite, type CallStatement, type ClassAccessibility, 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 GlobalCall, type GlobalValue, 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, LANGUAGE_GLOBALS, 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 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 TypeParamType, type TypePredicate, type TypePredicateNode, type TypeReference, type TypedIdentifier, type TypeofTypeNode, UNUSED_EXPECT_ERROR, type UnaryExpression, UnaryOperators, type UnionType, type UnionTypeNode, type UnknownType, type VariableDeclaration, 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, tupleMembers, typeParam, unify, union, unknownType, widen, withAliasName, withoutAliasName };
1829
+ export { type AnalyzeTypesOptions, type AnyType, type ArgumentInfo, 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 CallLowering, type CallSite, type CallStatement, type ClassAccessibility, 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 GlobalCall, type GlobalValue, 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, LANGUAGE_GLOBALS, 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 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 TypeParamType, type TypePredicate, type TypePredicateNode, type TypeReference, type TypedIdentifier, type TypeofTypeNode, UNUSED_EXPECT_ERROR, type UnaryExpression, UnaryOperators, type Unification, type UnionType, type UnionTypeNode, type UnknownType, type VariableDeclaration, 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, tupleMembers, typeParam, unify, union, unknownType, widen, withAliasName, withoutAliasName };
package/dist/index.d.ts CHANGED
@@ -1377,7 +1377,15 @@ declare function tupleMembers(t: TupleType): Type[];
1377
1377
  declare function objectType(entries: Iterable<[string, ObjectProperty]>, indexer?: ObjectType["indexer"], frozen?: boolean): ObjectType;
1378
1378
  declare function fn(params: FunctionParam[], returns: Type, varargs?: Type, typeParams?: string[], predicate?: TypePredicate): FunctionType;
1379
1379
  declare function substitute(t: Type, subst: Map<string, Type>): Type;
1380
- declare function unify(param: Type, arg: Type, vars: Set<string>, out: Map<string, Type>): void;
1380
+ /** How a type parameter takes a second candidate, at the top of a
1381
+ * parameter. Below it — a list's elements, a tuple's places — every
1382
+ * candidate is the same site and they gather, whichever mode was asked for. Arguments collected by
1383
+ * one `...rest: T[]` are all of them equally, so `firstOf(1, "a")` reads
1384
+ * `T` as their union. Two parameters written separately are not: the one
1385
+ * written first says what `T` is, and an argument that disagrees with it is
1386
+ * a mistake to report rather than a reason to widen. */
1387
+ type Unification = "union" | "first";
1388
+ declare function unify(param: Type, arg: Type, vars: Set<string>, out: Map<string, Type>, how?: Unification): void;
1381
1389
  declare function union(types: Type[]): Type;
1382
1390
  declare function intersection(types: Type[]): Type;
1383
1391
  /** `base - excluded`, simplified as far as the base allows. */
@@ -1818,4 +1826,4 @@ declare const tilua: {
1818
1826
  readonly analyzeTypes: typeof analyzeTypes;
1819
1827
  };
1820
1828
 
1821
- export { type AnalyzeTypesOptions, type AnyType, type ArgumentInfo, 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 CallLowering, type CallSite, type CallStatement, type ClassAccessibility, 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 GlobalCall, type GlobalValue, 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, LANGUAGE_GLOBALS, 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 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 TypeParamType, type TypePredicate, type TypePredicateNode, type TypeReference, type TypedIdentifier, type TypeofTypeNode, UNUSED_EXPECT_ERROR, type UnaryExpression, UnaryOperators, type UnionType, type UnionTypeNode, type UnknownType, type VariableDeclaration, 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, tupleMembers, typeParam, unify, union, unknownType, widen, withAliasName, withoutAliasName };
1829
+ export { type AnalyzeTypesOptions, type AnyType, type ArgumentInfo, 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 CallLowering, type CallSite, type CallStatement, type ClassAccessibility, 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 GlobalCall, type GlobalValue, 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, LANGUAGE_GLOBALS, 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 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 TypeParamType, type TypePredicate, type TypePredicateNode, type TypeReference, type TypedIdentifier, type TypeofTypeNode, UNUSED_EXPECT_ERROR, type UnaryExpression, UnaryOperators, type Unification, type UnionType, type UnionTypeNode, type UnknownType, type VariableDeclaration, 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, tupleMembers, typeParam, unify, union, unknownType, widen, withAliasName, withoutAliasName };
package/dist/index.js CHANGED
@@ -4565,14 +4565,17 @@ function classArguments(t, name) {
4565
4565
  if (t.kind === "object") return t.class?.typeArguments?.get(name);
4566
4566
  return void 0;
4567
4567
  }
4568
- function unify(param, arg, vars, out) {
4568
+ function unify(param, arg, vars, out, how = "union") {
4569
4569
  if (param.kind === "typeParam" && param.constraint && !vars.has(param.name)) {
4570
- unify(param.constraint, arg, vars, out);
4570
+ unify(param.constraint, arg, vars, out, how);
4571
4571
  return;
4572
4572
  }
4573
4573
  if (param.kind === "typeParam" && vars.has(param.name)) {
4574
4574
  const prev = out.get(param.name);
4575
- out.set(param.name, prev ? union([prev, arg]) : arg);
4575
+ if (!prev) out.set(param.name, arg);
4576
+ else if (isAssignable(arg, prev)) {
4577
+ } else if (isAssignable(prev, arg)) out.set(param.name, arg);
4578
+ else if (how === "union") out.set(param.name, union([prev, arg]));
4576
4579
  return;
4577
4580
  }
4578
4581
  if (arg.kind === "any" || arg.kind === "never") return;
@@ -7757,8 +7760,10 @@ var TypeAnalyzer = class {
7757
7760
  // --------------------------------------------------------
7758
7761
  // Functions
7759
7762
  // --------------------------------------------------------
7760
- visitFunctionBody(func, outerEnv) {
7761
- this.withTypeParams(func.generics, () => this.visitFunctionBodyInner(func, outerEnv));
7763
+ /** `returns`, when given, collects the type of each `return` the walk
7764
+ * reads — see `inferFunctionBody`. */
7765
+ visitFunctionBody(func, outerEnv, returns) {
7766
+ this.withTypeParams(func.generics, () => this.visitFunctionBodyInner(func, outerEnv, returns));
7762
7767
  }
7763
7768
  /** A parameter's type: annotation, else a shape synthesized from a
7764
7769
  * destructuring pattern, else inferred from its default, else `any`. */
@@ -7807,6 +7812,53 @@ var TypeAnalyzer = class {
7807
7812
  * it, as in TypeScript: `signal:Connect(function(player) ... end)` knows
7808
7813
  * `player` from `Connect`'s callback type. Anything else is inferred as
7809
7814
  * usual. */
7815
+ /** The arguments of a call, in two passes where one is needed.
7816
+ *
7817
+ * A function written at the call site with a parameter nothing annotates
7818
+ * reads that parameter from the signature — and where the signature says
7819
+ * `(v: T) => U`, `T` is only known once the other arguments have been
7820
+ * read. So such an argument is read once quietly, to get a shape to pick
7821
+ * a signature with, and then again with `T` in hand: `map(xs, v => v + 1)`
7822
+ * has its `v` a number by then, and `U` follows from what the body
7823
+ * answers. Everything else is read once, as it always was. */
7824
+ inferArguments(written, fns, selfOf, extra, env) {
7825
+ const expected = this.expectedArguments(written, fns, selfOf);
7826
+ written.forEach((a, i) => this.applyContext(a, expected[i]));
7827
+ const waits = written.map((a, i) => this.waitsOnInference(a, expected[i]));
7828
+ if (!waits.some(Boolean)) return written.map((a) => this.infer(a, env));
7829
+ const argTypes = written.map((a, i) => waits[i] ? this.quietly(() => this.infer(a, env)) : this.infer(a, env));
7830
+ const picked = this.pickOverload(fns, argTypes, (f) => extra(f, argTypes), this.spreadOf(written, selfOf(fns[0])));
7831
+ const subst = picked?.typeParams?.length ? this.inferTypeArgs(picked, extra(picked, argTypes)) : void 0;
7832
+ written.forEach((a, i) => {
7833
+ if (!waits[i]) return;
7834
+ if (picked && subst) {
7835
+ const self = selfOf(picked);
7836
+ const declared = i + self < picked.params.length ? picked.params[i + self].type : picked.varargs;
7837
+ if (declared) this.applyContext(a, this.reduceType(substitute(declared, subst)));
7838
+ }
7839
+ argTypes[i] = this.infer(a, env);
7840
+ });
7841
+ return argTypes;
7842
+ }
7843
+ /** Is this argument a function whose own type waits on the call's? */
7844
+ waitsOnInference(arg, expected) {
7845
+ if (!expected || !containsTypeParam(expected)) return false;
7846
+ let e = arg;
7847
+ while (e.type === "ParenthesizedExpression") e = e.expression;
7848
+ if (e.type !== "FunctionExpression") return false;
7849
+ return e.func.params.some((p) => !p.typeAnnotation && !p.default && !p.pattern && p.name !== "self" && p.name !== "this");
7850
+ }
7851
+ /** Read something without saying anything about it: a first pass whose
7852
+ * only purpose is a shape to go on. */
7853
+ quietly(read) {
7854
+ const was = this.emitDiagnostics;
7855
+ this.emitDiagnostics = false;
7856
+ try {
7857
+ return read();
7858
+ } finally {
7859
+ this.emitDiagnostics = was;
7860
+ }
7861
+ }
7810
7862
  applyContext(expr, expected) {
7811
7863
  let e = expr;
7812
7864
  while (e.type === "ParenthesizedExpression") e = e.expression;
@@ -7955,7 +8007,7 @@ var TypeAnalyzer = class {
7955
8007
  this.contextualReturns.pop();
7956
8008
  }
7957
8009
  }
7958
- visitFunctionBodyInner(func, outerEnv) {
8010
+ visitFunctionBodyInner(func, outerEnv, returns) {
7959
8011
  const env = forkEnv(outerEnv);
7960
8012
  for (const p of func.params) {
7961
8013
  if (p.pattern) {
@@ -7972,7 +8024,7 @@ var TypeAnalyzer = class {
7972
8024
  if (p.typeAnnotation) this.annotated.add(id);
7973
8025
  }
7974
8026
  }
7975
- this.withVarargs(func, () => this.collectReturns(void 0, () => {
8027
+ this.withVarargs(func, () => this.collectReturns(returns, () => {
7976
8028
  this.visitBlock(func.body, env);
7977
8029
  this.checkReturnsAtAll(func, this.declaredReturns[this.declaredReturns.length - 1]);
7978
8030
  }));
@@ -8026,7 +8078,7 @@ var TypeAnalyzer = class {
8026
8078
  if (arg === void 0) return;
8027
8079
  const param = p.type.kind === "typeParam" && p.type.constraint ? { ...p.type, constraint: this.reduceType(p.type.constraint) } : p.type;
8028
8080
  const preserve = keepsLiterals(param) || param.kind !== "typeParam" && containsTypeParam(param);
8029
- unify(p.type, preserve ? arg : widen(arg), vars, subst);
8081
+ unify(p.type, preserve ? arg : widen(arg), vars, subst, "first");
8030
8082
  });
8031
8083
  if (f.varargs && f.restIsWhole) {
8032
8084
  const rest = argTypes.slice(f.params.length).map((a) => a === void 0 ? unknownType : widen(a));
@@ -8377,7 +8429,12 @@ var TypeAnalyzer = class {
8377
8429
  asserts: node.asserts
8378
8430
  };
8379
8431
  }
8380
- inferFunctionBody(func, env) {
8432
+ /** `visited`, when given, is what the real walk of the body just
8433
+ * collected from its `return`s: a function expression is walked before
8434
+ * its type is asked for, so there is nothing left to guess, and walking
8435
+ * the body a second time only to read them made every callback nested in
8436
+ * another cost twice its parent's. */
8437
+ inferFunctionBody(func, env, visited) {
8381
8438
  const names = func.generics.map((g) => g.name);
8382
8439
  return this.withTypeParams(func.generics, () => {
8383
8440
  const params = func.params.flatMap((p) => {
@@ -8406,6 +8463,8 @@ var TypeAnalyzer = class {
8406
8463
  returns = this.resolveType(func.returnType);
8407
8464
  } else if (func.predicate) {
8408
8465
  returns = booleanType;
8466
+ } else if (visited) {
8467
+ returns = visited.length ? union([...visited]) : this.withVarargs(func, () => this.silently(() => this.inferReturnType(func.body, bodyEnv)));
8409
8468
  } else {
8410
8469
  const collected = [];
8411
8470
  returns = this.withVarargs(func, () => this.silently(() => {
@@ -9278,10 +9337,12 @@ var TypeAnalyzer = class {
9278
9337
  return this.inferArray(expr, env, false);
9279
9338
  case "TableExpression":
9280
9339
  return this.inferObject(expr, env, false);
9281
- case "FunctionExpression":
9340
+ case "FunctionExpression": {
9282
9341
  this.checkParamOrder(expr.func.params, expr);
9283
- this.visitFunctionBody(expr.func, env);
9284
- return this.inferFunctionBody(expr.func, env);
9342
+ const returned = [];
9343
+ this.visitFunctionBody(expr.func, env, returned);
9344
+ return this.inferFunctionBody(expr.func, env, returned);
9345
+ }
9285
9346
  case "ParenthesizedExpression":
9286
9347
  return this.infer(expr.expression, env);
9287
9348
  case "TypeAssertionExpression": {
@@ -9485,9 +9546,7 @@ var TypeAnalyzer = class {
9485
9546
  const united = this.unionSignatures(callee);
9486
9547
  const fns = united ?? this.overloadsOf(callee);
9487
9548
  const explicit = this.explicitTypeArguments(expr, fns);
9488
- const expected = this.expectedArguments(expr.arguments, fns, () => 0);
9489
- expr.arguments.forEach((a, i) => this.applyContext(a, expected[i]));
9490
- const argTypes = expr.arguments.map((a) => this.infer(a, env));
9549
+ const argTypes = this.inferArguments(expr.arguments, fns, () => 0, (_, args) => args, env);
9491
9550
  if (fns.length) {
9492
9551
  this.recordExpected(expr.arguments, fns, () => 0, () => argTypes);
9493
9552
  const spread = this.spreadOf(expr.arguments);
@@ -9552,9 +9611,13 @@ var TypeAnalyzer = class {
9552
9611
  const united = this.unionSignatures(method);
9553
9612
  const fns = united ?? this.overloadsOf(method);
9554
9613
  const explicit = this.explicitTypeArguments(expr, fns);
9555
- const expected = this.expectedArguments(expr.arguments, fns, (f) => this.takesSelf(f) ? 1 : 0);
9556
- expr.arguments.forEach((a, i) => this.applyContext(a, expected[i]));
9557
- const argTypes = expr.arguments.map((a) => this.infer(a, env));
9614
+ const argTypes = this.inferArguments(
9615
+ expr.arguments,
9616
+ fns,
9617
+ (f) => this.takesSelf(f) ? 1 : 0,
9618
+ (f, args) => this.takesSelf(f) ? [objType, ...args] : args,
9619
+ env
9620
+ );
9558
9621
  if (fns.length) {
9559
9622
  const withSelf = (f) => this.takesSelf(f) ? [objType, ...argTypes] : argTypes;
9560
9623
  const selfOf = (f) => this.takesSelf(f) ? 1 : 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tilua/parser",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "tilua parser for roblox",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",