@thigasdevelopment/luam 0.9.0 → 0.10.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 +269 -13
- package/package.json +1 -1
package/luam.mjs
CHANGED
|
@@ -3534,6 +3534,7 @@ var SYMBOLS = [
|
|
|
3534
3534
|
">",
|
|
3535
3535
|
"=",
|
|
3536
3536
|
"|",
|
|
3537
|
+
"&",
|
|
3537
3538
|
"?",
|
|
3538
3539
|
"@",
|
|
3539
3540
|
"(",
|
|
@@ -3685,7 +3686,8 @@ function scan(source) {
|
|
|
3685
3686
|
}
|
|
3686
3687
|
|
|
3687
3688
|
// ../compiler/src/parser/type-annotation.ts
|
|
3688
|
-
var TYPE_KEYWORDS = /* @__PURE__ */ new Set(["nil"
|
|
3689
|
+
var TYPE_KEYWORDS = /* @__PURE__ */ new Set(["nil"]);
|
|
3690
|
+
var BOOLEAN_KEYWORDS = /* @__PURE__ */ new Set(["true", "false"]);
|
|
3689
3691
|
var FUNCTION_TYPE = "fun";
|
|
3690
3692
|
function parseTypeName(stream) {
|
|
3691
3693
|
const token = stream.current();
|
|
@@ -3775,11 +3777,24 @@ function parseObjectType(stream) {
|
|
|
3775
3777
|
stream.expect("punctuation", "}");
|
|
3776
3778
|
return { kind: "type-object", members, position: position2 };
|
|
3777
3779
|
}
|
|
3780
|
+
function parseNumberLiteralType(stream) {
|
|
3781
|
+
const sign = stream.check("operator", "-") ? stream.next() : null;
|
|
3782
|
+
const token = stream.expect("number");
|
|
3783
|
+
const value = Number(token.value);
|
|
3784
|
+
return { kind: "type-number-literal", value: sign === null ? value : -value, position: sign?.position ?? token.position };
|
|
3785
|
+
}
|
|
3778
3786
|
function parsePrimaryType(stream) {
|
|
3779
3787
|
if (stream.check("string")) {
|
|
3780
3788
|
const token = stream.next();
|
|
3781
3789
|
return { kind: "type-string-literal", value: token.value, position: token.position };
|
|
3782
3790
|
}
|
|
3791
|
+
if (stream.check("number") || stream.check("operator", "-") && stream.checkAhead(1, "number")) {
|
|
3792
|
+
return parseNumberLiteralType(stream);
|
|
3793
|
+
}
|
|
3794
|
+
if (stream.check("keyword") && BOOLEAN_KEYWORDS.has(stream.current().value)) {
|
|
3795
|
+
const token = stream.next();
|
|
3796
|
+
return { kind: "type-boolean-literal", value: token.value === "true", position: token.position };
|
|
3797
|
+
}
|
|
3783
3798
|
if (stream.check("keyword", "function")) {
|
|
3784
3799
|
throw stream.error(`Use "${FUNCTION_TYPE}" for function types. "function" is a keyword and cannot name a type.`, "parse-invalid-type");
|
|
3785
3800
|
}
|
|
@@ -3809,14 +3824,25 @@ function parsePostfixType(stream) {
|
|
|
3809
3824
|
return annotation;
|
|
3810
3825
|
}
|
|
3811
3826
|
}
|
|
3812
|
-
function
|
|
3827
|
+
function parseIntersectionType(stream) {
|
|
3813
3828
|
const first = parsePostfixType(stream);
|
|
3829
|
+
if (!stream.check("operator", "&")) {
|
|
3830
|
+
return first;
|
|
3831
|
+
}
|
|
3832
|
+
const parts = [first];
|
|
3833
|
+
while (stream.match("operator", "&")) {
|
|
3834
|
+
parts.push(parsePostfixType(stream));
|
|
3835
|
+
}
|
|
3836
|
+
return { kind: "type-intersection", parts, position: first.position };
|
|
3837
|
+
}
|
|
3838
|
+
function parseTypeAnnotation(stream) {
|
|
3839
|
+
const first = parseIntersectionType(stream);
|
|
3814
3840
|
if (!stream.check("operator", "|")) {
|
|
3815
3841
|
return first;
|
|
3816
3842
|
}
|
|
3817
3843
|
const options = [first];
|
|
3818
3844
|
while (stream.match("operator", "|")) {
|
|
3819
|
-
options.push(
|
|
3845
|
+
options.push(parseIntersectionType(stream));
|
|
3820
3846
|
}
|
|
3821
3847
|
return { kind: "type-union", options, position: first.position };
|
|
3822
3848
|
}
|
|
@@ -4780,7 +4806,22 @@ function createMap(key, value) {
|
|
|
4780
4806
|
function createStringLiteral(value) {
|
|
4781
4807
|
return { kind: "string-literal", value };
|
|
4782
4808
|
}
|
|
4809
|
+
function createBooleanLiteral(value) {
|
|
4810
|
+
return { kind: "boolean-literal", value };
|
|
4811
|
+
}
|
|
4812
|
+
function createNumberLiteral(value) {
|
|
4813
|
+
return { kind: "number-literal", value };
|
|
4814
|
+
}
|
|
4815
|
+
function isLiteralType(type) {
|
|
4816
|
+
return type.kind === "string-literal" || type.kind === "boolean-literal" || type.kind === "number-literal";
|
|
4817
|
+
}
|
|
4783
4818
|
function widenLiteral(type) {
|
|
4819
|
+
if (type.kind === "boolean-literal") {
|
|
4820
|
+
return BOOLEAN_TYPE;
|
|
4821
|
+
}
|
|
4822
|
+
if (type.kind === "number-literal") {
|
|
4823
|
+
return NUMBER_TYPE;
|
|
4824
|
+
}
|
|
4784
4825
|
return type.kind === "string-literal" ? STRING_TYPE : type;
|
|
4785
4826
|
}
|
|
4786
4827
|
function createRecord(name, members, origin = null) {
|
|
@@ -4865,6 +4906,9 @@ function typeToString(type) {
|
|
|
4865
4906
|
if (type.kind === "string-literal") {
|
|
4866
4907
|
return `'${type.value.replace(/(['\\])/g, "\\$1")}'`;
|
|
4867
4908
|
}
|
|
4909
|
+
if (type.kind === "boolean-literal" || type.kind === "number-literal") {
|
|
4910
|
+
return String(type.value);
|
|
4911
|
+
}
|
|
4868
4912
|
if (type.kind === "named" || type.kind === "record") {
|
|
4869
4913
|
return type.name;
|
|
4870
4914
|
}
|
|
@@ -4900,13 +4944,13 @@ function isTableLike(type) {
|
|
|
4900
4944
|
}
|
|
4901
4945
|
function isBooleanType(type) {
|
|
4902
4946
|
const resolved2 = type?.kind === "optional" ? type.element : type;
|
|
4903
|
-
return resolved2?.kind === "boolean";
|
|
4947
|
+
return resolved2?.kind === "boolean" || resolved2?.kind === "boolean-literal";
|
|
4904
4948
|
}
|
|
4905
4949
|
function isNumeric(type) {
|
|
4906
4950
|
if (type.kind === "union") {
|
|
4907
4951
|
return type.options.every(isNumeric);
|
|
4908
4952
|
}
|
|
4909
|
-
return type.kind === "number" || type.kind === "any" || type.kind === "unknown" || type.kind === "named";
|
|
4953
|
+
return type.kind === "number" || type.kind === "number-literal" || type.kind === "any" || type.kind === "unknown" || type.kind === "named";
|
|
4910
4954
|
}
|
|
4911
4955
|
function isConcatenable(type) {
|
|
4912
4956
|
if (type.kind === "union") {
|
|
@@ -5001,7 +5045,13 @@ function isAssignable(source, target, options = { allowNil: false }) {
|
|
|
5001
5045
|
if (source.kind === "string-literal") {
|
|
5002
5046
|
return target.kind === "string" || target.kind === "string-literal" && source.value === target.value;
|
|
5003
5047
|
}
|
|
5004
|
-
if (
|
|
5048
|
+
if (source.kind === "boolean-literal") {
|
|
5049
|
+
return target.kind === "boolean" || target.kind === "boolean-literal" && source.value === target.value;
|
|
5050
|
+
}
|
|
5051
|
+
if (source.kind === "number-literal") {
|
|
5052
|
+
return target.kind === "number" || target.kind === "number-literal" && source.value === target.value;
|
|
5053
|
+
}
|
|
5054
|
+
if (isLiteralType(target)) {
|
|
5005
5055
|
return false;
|
|
5006
5056
|
}
|
|
5007
5057
|
return source.kind === target.kind;
|
|
@@ -5987,7 +6037,7 @@ import { tmpdir } from "node:os";
|
|
|
5987
6037
|
import { join as join2 } from "node:path";
|
|
5988
6038
|
|
|
5989
6039
|
// src/cli/version.ts
|
|
5990
|
-
var VERSION = true ? "0.
|
|
6040
|
+
var VERSION = true ? "0.10.1" : "0.0.0-dev";
|
|
5991
6041
|
var PROGRAM_NAME = "luam";
|
|
5992
6042
|
var PROGRAM_DESCRIPTION = "luam \u2014 the Luam compiler for Multi Theft Auto resources.";
|
|
5993
6043
|
|
|
@@ -7186,6 +7236,9 @@ var Binder = class {
|
|
|
7186
7236
|
lookupAlias(name) {
|
|
7187
7237
|
return this.aliases.get(name) ?? null;
|
|
7188
7238
|
}
|
|
7239
|
+
resolvedAliases() {
|
|
7240
|
+
return new Map([...this.aliases].map(([name, info]) => [name, info.type]));
|
|
7241
|
+
}
|
|
7189
7242
|
};
|
|
7190
7243
|
|
|
7191
7244
|
// ../mta-types/src/lua-standard.ts
|
|
@@ -11021,6 +11074,41 @@ function mtaMember(className, member) {
|
|
|
11021
11074
|
return mtaClassRegistry().lookupMember(className, member);
|
|
11022
11075
|
}
|
|
11023
11076
|
|
|
11077
|
+
// ../compiler/src/checker/type-intersection.ts
|
|
11078
|
+
function namedMembers(context, name) {
|
|
11079
|
+
if (context.declarations.lookupInterface(name) === null && context.declarations.lookupClass(name) === null) {
|
|
11080
|
+
return null;
|
|
11081
|
+
}
|
|
11082
|
+
return new Map(context.declarations.collectMembers(name).map((member) => [member.name, member.type]));
|
|
11083
|
+
}
|
|
11084
|
+
function partMembers(context, part) {
|
|
11085
|
+
if (part.kind === "record") {
|
|
11086
|
+
return part.members;
|
|
11087
|
+
}
|
|
11088
|
+
return part.kind === "named" ? namedMembers(context, part.name) : null;
|
|
11089
|
+
}
|
|
11090
|
+
function mergeIntersection(context, parts, position2) {
|
|
11091
|
+
const members = /* @__PURE__ */ new Map();
|
|
11092
|
+
for (const part of parts) {
|
|
11093
|
+
const collected = partMembers(context, part);
|
|
11094
|
+
if (collected === null) {
|
|
11095
|
+
const message = `"${typeToString(part)}" is not an object type, so it cannot take part in an intersection.`;
|
|
11096
|
+
context.report("check-invalid-intersection", message, position2);
|
|
11097
|
+
continue;
|
|
11098
|
+
}
|
|
11099
|
+
for (const [name, type] of collected) {
|
|
11100
|
+
const existing = members.get(name);
|
|
11101
|
+
if (existing !== void 0 && typeToString(existing) !== typeToString(type)) {
|
|
11102
|
+
const message = `Intersection declares "${name}" as both "${typeToString(existing)}" and "${typeToString(type)}".`;
|
|
11103
|
+
context.report("check-conflicting-intersection-member", message, position2);
|
|
11104
|
+
continue;
|
|
11105
|
+
}
|
|
11106
|
+
members.set(name, type);
|
|
11107
|
+
}
|
|
11108
|
+
}
|
|
11109
|
+
return createObjectType(members);
|
|
11110
|
+
}
|
|
11111
|
+
|
|
11024
11112
|
// ../compiler/src/checker/type-substitution.ts
|
|
11025
11113
|
function substituteType(type, substitutions) {
|
|
11026
11114
|
if (type.kind === "named") {
|
|
@@ -11085,6 +11173,8 @@ var CheckContext = class {
|
|
|
11085
11173
|
references = /* @__PURE__ */ new Set();
|
|
11086
11174
|
declaredGlobals = /* @__PURE__ */ new Map();
|
|
11087
11175
|
externalReferences = /* @__PURE__ */ new Map();
|
|
11176
|
+
unknownTypes = /* @__PURE__ */ new Map();
|
|
11177
|
+
typeParameters = /* @__PURE__ */ new Set();
|
|
11088
11178
|
generatedMembers = /* @__PURE__ */ new Map();
|
|
11089
11179
|
mode;
|
|
11090
11180
|
environment;
|
|
@@ -11145,6 +11235,12 @@ var CheckContext = class {
|
|
|
11145
11235
|
}
|
|
11146
11236
|
}
|
|
11147
11237
|
report(code, message, position2) {
|
|
11238
|
+
this.push(code, message, position2, "error");
|
|
11239
|
+
}
|
|
11240
|
+
warn(code, message, position2) {
|
|
11241
|
+
this.push(code, message, position2, "warning");
|
|
11242
|
+
}
|
|
11243
|
+
push(code, message, position2, severity) {
|
|
11148
11244
|
if (this.mode === "nocheck") {
|
|
11149
11245
|
return;
|
|
11150
11246
|
}
|
|
@@ -11153,7 +11249,20 @@ var CheckContext = class {
|
|
|
11153
11249
|
return;
|
|
11154
11250
|
}
|
|
11155
11251
|
this.reported.add(key);
|
|
11156
|
-
this.diagnostics.push(createDiagnostic("checker", code, message, position2));
|
|
11252
|
+
this.diagnostics.push(createDiagnostic("checker", code, message, position2, severity));
|
|
11253
|
+
}
|
|
11254
|
+
noteTypeParameters(names) {
|
|
11255
|
+
for (const name of names) {
|
|
11256
|
+
this.typeParameters.add(name);
|
|
11257
|
+
}
|
|
11258
|
+
}
|
|
11259
|
+
isTypeParameter(name) {
|
|
11260
|
+
return this.typeParameters.has(name);
|
|
11261
|
+
}
|
|
11262
|
+
noteUnknownType(name, position2) {
|
|
11263
|
+
if (!this.unknownTypes.has(name)) {
|
|
11264
|
+
this.unknownTypes.set(name, position2);
|
|
11265
|
+
}
|
|
11157
11266
|
}
|
|
11158
11267
|
record(expression, type) {
|
|
11159
11268
|
this.types.set(expression, type);
|
|
@@ -11212,9 +11321,19 @@ var CheckContext = class {
|
|
|
11212
11321
|
if (annotation.kind === "type-union") {
|
|
11213
11322
|
return createUnion(annotation.options.map((option) => this.resolveAnnotation(option)));
|
|
11214
11323
|
}
|
|
11324
|
+
if (annotation.kind === "type-intersection") {
|
|
11325
|
+
const parts = annotation.parts.map((part) => this.resolveAnnotation(part));
|
|
11326
|
+
return mergeIntersection(this, parts, annotation.position);
|
|
11327
|
+
}
|
|
11215
11328
|
if (annotation.kind === "type-string-literal") {
|
|
11216
11329
|
return createStringLiteral(annotation.value);
|
|
11217
11330
|
}
|
|
11331
|
+
if (annotation.kind === "type-boolean-literal") {
|
|
11332
|
+
return createBooleanLiteral(annotation.value);
|
|
11333
|
+
}
|
|
11334
|
+
if (annotation.kind === "type-number-literal") {
|
|
11335
|
+
return createNumberLiteral(annotation.value);
|
|
11336
|
+
}
|
|
11218
11337
|
if (annotation.kind === "type-object") {
|
|
11219
11338
|
const members = /* @__PURE__ */ new Map();
|
|
11220
11339
|
for (const member of annotation.members) {
|
|
@@ -11237,7 +11356,7 @@ var CheckContext = class {
|
|
|
11237
11356
|
if (isAssignable(source, target, { allowNil: this.allowNil })) {
|
|
11238
11357
|
return;
|
|
11239
11358
|
}
|
|
11240
|
-
const received = target
|
|
11359
|
+
const received = isLiteralType(target) || target.kind === "union" ? source : widenLiteral(source);
|
|
11241
11360
|
const message = `${subject} expects "${typeToString(target)}" but received "${typeToString(received)}".`;
|
|
11242
11361
|
this.report("check-type-mismatch", `${message}${nilHint(source, target, this.mode)}`, position2);
|
|
11243
11362
|
}
|
|
@@ -11293,6 +11412,7 @@ var CheckContext = class {
|
|
|
11293
11412
|
}
|
|
11294
11413
|
const alias = this.binder.lookupAlias(name);
|
|
11295
11414
|
if (alias === null) {
|
|
11415
|
+
this.noteUnknownType(name, position2);
|
|
11296
11416
|
return createNamed(name);
|
|
11297
11417
|
}
|
|
11298
11418
|
if (typeArguments.length !== alias.parameters.length) {
|
|
@@ -12277,6 +12397,9 @@ function checkUnary(context, operator, operand, expression) {
|
|
|
12277
12397
|
if (operator === "-" && !isNumeric(operand)) {
|
|
12278
12398
|
reportInvalidOperand(context, operator, operand, expression);
|
|
12279
12399
|
}
|
|
12400
|
+
if (operator === "-" && operand.kind === "number-literal") {
|
|
12401
|
+
return context.record(expression, createNumberLiteral(-operand.value));
|
|
12402
|
+
}
|
|
12280
12403
|
return context.record(expression, NUMBER_TYPE);
|
|
12281
12404
|
}
|
|
12282
12405
|
|
|
@@ -12304,6 +12427,47 @@ function templateLiteralText(segments) {
|
|
|
12304
12427
|
return segments.map((segment) => segment.kind === "text" ? segment.value : `\${${segment.value}}`).join("");
|
|
12305
12428
|
}
|
|
12306
12429
|
|
|
12430
|
+
// ../compiler/src/checker/union-members.ts
|
|
12431
|
+
function isShapeOption(context, option) {
|
|
12432
|
+
if (option.kind === "record") {
|
|
12433
|
+
return true;
|
|
12434
|
+
}
|
|
12435
|
+
if (option.kind !== "named") {
|
|
12436
|
+
return false;
|
|
12437
|
+
}
|
|
12438
|
+
return context.declarations.lookupInterface(option.name) !== null || context.declarations.lookupClass(option.name) !== null;
|
|
12439
|
+
}
|
|
12440
|
+
function memberOf(context, option, property) {
|
|
12441
|
+
if (option.kind === "record") {
|
|
12442
|
+
return option.members.get(property) ?? null;
|
|
12443
|
+
}
|
|
12444
|
+
return option.kind === "named" ? context.declarations.lookupMember(option.name, property)?.type ?? null : null;
|
|
12445
|
+
}
|
|
12446
|
+
function optionMemberType(context, option, property) {
|
|
12447
|
+
return isShapeOption(context, option) ? memberOf(context, option, property) : null;
|
|
12448
|
+
}
|
|
12449
|
+
function resolveUnionMember(context, type, expression) {
|
|
12450
|
+
if (!type.options.every((option) => isShapeOption(context, option))) {
|
|
12451
|
+
return null;
|
|
12452
|
+
}
|
|
12453
|
+
const resolved2 = [];
|
|
12454
|
+
const missing = [];
|
|
12455
|
+
for (const option of type.options) {
|
|
12456
|
+
const member = memberOf(context, option, expression.property);
|
|
12457
|
+
if (member === null) {
|
|
12458
|
+
missing.push(`"${typeToString(option)}"`);
|
|
12459
|
+
} else {
|
|
12460
|
+
resolved2.push(member);
|
|
12461
|
+
}
|
|
12462
|
+
}
|
|
12463
|
+
if (missing.length === 0) {
|
|
12464
|
+
return createUnion(resolved2);
|
|
12465
|
+
}
|
|
12466
|
+
const message = `"${expression.property}" is not a key of every member of "${typeToString(type)}". It is missing from ${missing.join(", ")}.`;
|
|
12467
|
+
context.report("check-unknown-union-key", message, expression.position);
|
|
12468
|
+
return ANY_TYPE;
|
|
12469
|
+
}
|
|
12470
|
+
|
|
12307
12471
|
// ../compiler/src/checker/expressions.ts
|
|
12308
12472
|
var EXTENSION_RESULTS = {
|
|
12309
12473
|
boolean: BOOLEAN_TYPE,
|
|
@@ -12312,7 +12476,8 @@ var EXTENSION_RESULTS = {
|
|
|
12312
12476
|
table: TABLE_TYPE
|
|
12313
12477
|
};
|
|
12314
12478
|
function extensionType(receiver, property) {
|
|
12315
|
-
const
|
|
12479
|
+
const literal = receiver.kind === "string-literal" ? "string" : receiver.kind === "number-literal" ? "number" : null;
|
|
12480
|
+
const kind = literal ?? (receiver.kind === "string" || receiver.kind === "number" ? receiver.kind : null);
|
|
12316
12481
|
const target = kind ?? (isTableLike(receiver) ? "table" : null);
|
|
12317
12482
|
if (target === null) {
|
|
12318
12483
|
return null;
|
|
@@ -12346,6 +12511,12 @@ function checkMember(context, expression) {
|
|
|
12346
12511
|
if (objectType.kind === "record") {
|
|
12347
12512
|
return context.record(expression, resolveRecordMember(context, objectType, expression));
|
|
12348
12513
|
}
|
|
12514
|
+
if (objectType.kind === "union") {
|
|
12515
|
+
const option = resolveUnionMember(context, objectType, expression);
|
|
12516
|
+
if (option !== null) {
|
|
12517
|
+
return context.record(expression, option);
|
|
12518
|
+
}
|
|
12519
|
+
}
|
|
12349
12520
|
if (objectType.kind === "map" && isAssignable(STRING_TYPE, objectType.key)) {
|
|
12350
12521
|
return context.record(expression, objectType.value);
|
|
12351
12522
|
}
|
|
@@ -12454,9 +12625,9 @@ function checkMultiValueExpression(context, expression) {
|
|
|
12454
12625
|
case "nil-literal":
|
|
12455
12626
|
return context.record(expression, NIL_TYPE);
|
|
12456
12627
|
case "boolean-literal":
|
|
12457
|
-
return context.record(expression,
|
|
12628
|
+
return context.record(expression, createBooleanLiteral(expression.value));
|
|
12458
12629
|
case "number-literal":
|
|
12459
|
-
return context.record(expression,
|
|
12630
|
+
return context.record(expression, createNumberLiteral(expression.value));
|
|
12460
12631
|
case "string-literal":
|
|
12461
12632
|
return context.record(expression, createStringLiteral(expression.value));
|
|
12462
12633
|
case "template-literal":
|
|
@@ -12702,6 +12873,53 @@ function checkEnumDeclaration(context, statement) {
|
|
|
12702
12873
|
context.declareModuleGlobal({ name: statement.name, type: createNamed(statement.name), isLocal: false, position: statement.position });
|
|
12703
12874
|
}
|
|
12704
12875
|
|
|
12876
|
+
// ../compiler/src/checker/discriminant.ts
|
|
12877
|
+
function literalValue(expression) {
|
|
12878
|
+
if (expression.kind === "string-literal") {
|
|
12879
|
+
return createStringLiteral(expression.value);
|
|
12880
|
+
}
|
|
12881
|
+
if (expression.kind === "boolean-literal") {
|
|
12882
|
+
return createBooleanLiteral(expression.value);
|
|
12883
|
+
}
|
|
12884
|
+
return expression.kind === "number-literal" ? createNumberLiteral(expression.value) : null;
|
|
12885
|
+
}
|
|
12886
|
+
function discriminantTest(left, right) {
|
|
12887
|
+
if (left.kind !== "member-expression" || left.object.kind !== "identifier") {
|
|
12888
|
+
return null;
|
|
12889
|
+
}
|
|
12890
|
+
const value = literalValue(right);
|
|
12891
|
+
return value === null ? null : { name: left.object.name, property: left.property, value };
|
|
12892
|
+
}
|
|
12893
|
+
function subjectType(context, name) {
|
|
12894
|
+
const type = context.narrowedType(name) ?? context.binder.lookup(name)?.type ?? null;
|
|
12895
|
+
return type === null ? null : withoutNil(type);
|
|
12896
|
+
}
|
|
12897
|
+
function filterOptions(context, test, keep) {
|
|
12898
|
+
const subject = subjectType(context, test.name);
|
|
12899
|
+
if (subject === null || subject.kind !== "union") {
|
|
12900
|
+
return null;
|
|
12901
|
+
}
|
|
12902
|
+
const matched = [];
|
|
12903
|
+
for (const option of subject.options) {
|
|
12904
|
+
const member = optionMemberType(context, option, test.property);
|
|
12905
|
+
if (member === null) {
|
|
12906
|
+
return null;
|
|
12907
|
+
}
|
|
12908
|
+
if (isAssignable(test.value, member) === keep) {
|
|
12909
|
+
matched.push(option);
|
|
12910
|
+
}
|
|
12911
|
+
}
|
|
12912
|
+
return matched.length === 0 || matched.length === subject.options.length ? null : createUnion(matched);
|
|
12913
|
+
}
|
|
12914
|
+
function discriminantFact(context, left, right, keep) {
|
|
12915
|
+
const test = discriminantTest(left, right) ?? discriminantTest(right, left);
|
|
12916
|
+
if (test === null) {
|
|
12917
|
+
return null;
|
|
12918
|
+
}
|
|
12919
|
+
const narrowed = filterOptions(context, test, keep);
|
|
12920
|
+
return narrowed === null ? null : [test.name, narrowed];
|
|
12921
|
+
}
|
|
12922
|
+
|
|
12705
12923
|
// ../compiler/src/checker/narrowing.ts
|
|
12706
12924
|
var GUARD_FUNCTION = "type";
|
|
12707
12925
|
var GUARD_TYPES = {
|
|
@@ -12749,6 +12967,12 @@ function mergeAlternatives(left, right, facts) {
|
|
|
12749
12967
|
}
|
|
12750
12968
|
}
|
|
12751
12969
|
}
|
|
12970
|
+
function applyDiscriminant(context, left, right, keep, facts) {
|
|
12971
|
+
const fact = discriminantFact(context, left, right, keep);
|
|
12972
|
+
if (fact !== null) {
|
|
12973
|
+
facts.set(fact[0], fact[1]);
|
|
12974
|
+
}
|
|
12975
|
+
}
|
|
12752
12976
|
function collectFacts(context, expression, facts) {
|
|
12753
12977
|
if (expression.kind === "group-expression") {
|
|
12754
12978
|
collectFacts(context, expression.expression, facts);
|
|
@@ -12777,6 +13001,8 @@ function collectFacts(context, expression, facts) {
|
|
|
12777
13001
|
facts.set(guard[0], guard[1]);
|
|
12778
13002
|
} else if (missing !== null) {
|
|
12779
13003
|
facts.set(missing, NIL_TYPE);
|
|
13004
|
+
} else {
|
|
13005
|
+
applyDiscriminant(context, expression.left, expression.right, true, facts);
|
|
12780
13006
|
}
|
|
12781
13007
|
return;
|
|
12782
13008
|
}
|
|
@@ -12784,6 +13010,8 @@ function collectFacts(context, expression, facts) {
|
|
|
12784
13010
|
const name = nilComparison(expression.left, expression.right);
|
|
12785
13011
|
if (name !== null) {
|
|
12786
13012
|
present2(context, name, facts);
|
|
13013
|
+
} else {
|
|
13014
|
+
applyDiscriminant(context, expression.left, expression.right, false, facts);
|
|
12787
13015
|
}
|
|
12788
13016
|
}
|
|
12789
13017
|
}
|
|
@@ -12824,8 +13052,13 @@ function negatedFacts(context, condition) {
|
|
|
12824
13052
|
const name = nilComparison(condition.left, condition.right);
|
|
12825
13053
|
if (name !== null) {
|
|
12826
13054
|
present2(context, name, facts);
|
|
13055
|
+
} else {
|
|
13056
|
+
applyDiscriminant(context, condition.left, condition.right, false, facts);
|
|
12827
13057
|
}
|
|
12828
13058
|
}
|
|
13059
|
+
if (condition.kind === "binary-expression" && condition.operator === "~=") {
|
|
13060
|
+
applyDiscriminant(context, condition.left, condition.right, true, facts);
|
|
13061
|
+
}
|
|
12829
13062
|
if (condition.kind === "unary-expression" && condition.operator === "not" && condition.operand.kind === "identifier") {
|
|
12830
13063
|
present2(context, condition.operand.name, facts);
|
|
12831
13064
|
}
|
|
@@ -13082,7 +13315,9 @@ function checkStatement(context, statement) {
|
|
|
13082
13315
|
return checkGenericFor(context, statement);
|
|
13083
13316
|
case "type-alias-statement": {
|
|
13084
13317
|
const resolved2 = context.resolveAnnotation(statement.annotation);
|
|
13085
|
-
const
|
|
13318
|
+
const shape = statement.annotation.kind === "type-object" || statement.annotation.kind === "type-intersection";
|
|
13319
|
+
const named2 = shape ? renameRecord(resolved2, statement.name) : resolved2;
|
|
13320
|
+
context.noteTypeParameters(statement.typeParameters);
|
|
13086
13321
|
context.binder.declareAlias(statement.name, named2, statement.typeParameters);
|
|
13087
13322
|
return;
|
|
13088
13323
|
}
|
|
@@ -13114,6 +13349,25 @@ function checkStatements(context, statements) {
|
|
|
13114
13349
|
}
|
|
13115
13350
|
}
|
|
13116
13351
|
|
|
13352
|
+
// ../compiler/src/checker/type-names.ts
|
|
13353
|
+
function isDeclaredType(context, name) {
|
|
13354
|
+
const declarations = context.declarations;
|
|
13355
|
+
return declarations.lookupClass(name) !== null || declarations.lookupInterface(name) !== null || declarations.lookupEnum(name) !== null;
|
|
13356
|
+
}
|
|
13357
|
+
function isKnownTypeName(context, name) {
|
|
13358
|
+
if (context.binder.lookupAlias(name) !== null || context.isTypeParameter(name)) {
|
|
13359
|
+
return true;
|
|
13360
|
+
}
|
|
13361
|
+
return isDeclaredType(context, name) || isMtaClass(name);
|
|
13362
|
+
}
|
|
13363
|
+
function reportUnknownTypes(context) {
|
|
13364
|
+
for (const [name, position2] of context.unknownTypes) {
|
|
13365
|
+
if (!isKnownTypeName(context, name)) {
|
|
13366
|
+
context.warn("check-unknown-type", `Type "${name}" is not defined.`, position2);
|
|
13367
|
+
}
|
|
13368
|
+
}
|
|
13369
|
+
}
|
|
13370
|
+
|
|
13117
13371
|
// ../compiler/src/checker/checker.ts
|
|
13118
13372
|
function externalReferences(context) {
|
|
13119
13373
|
const external = /* @__PURE__ */ new Map();
|
|
@@ -13132,11 +13386,13 @@ function check(program2, mode, environment = DEFAULT_ENVIRONMENT, options = {})
|
|
|
13132
13386
|
const structure = context.isDeclarationFile ? checkDeclarationFile(program2.body) : checkJumps(program2.body);
|
|
13133
13387
|
const directives = collectDirectives(program2.body, { isDeclarationFile: context.isDeclarationFile });
|
|
13134
13388
|
checkStatements(context, program2.body);
|
|
13389
|
+
reportUnknownTypes(context);
|
|
13135
13390
|
return {
|
|
13136
13391
|
diagnostics: sortDiagnostics([...structure, ...directives.diagnostics, ...context.diagnostics]),
|
|
13137
13392
|
types: context.types,
|
|
13138
13393
|
references: context.references,
|
|
13139
13394
|
declarations: context.declarations,
|
|
13395
|
+
aliases: context.binder.resolvedAliases(),
|
|
13140
13396
|
declaredGlobals: context.declaredGlobals,
|
|
13141
13397
|
externalReferences: externalReferences(context),
|
|
13142
13398
|
directives: directives.directives,
|