@chenglou/freerange 0.0.3 → 0.0.4
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/CHANGELOG.md +7 -1
- package/README.md +3 -1
- package/dist/fr.js +356 -359
- package/package.json +1 -1
- package/src/audit.ts +0 -2
- package/src/ir/program.ts +0 -3
- package/src/lower/context.ts +3 -0
- package/src/lower/expression.ts +45 -55
- package/src/lower/module.ts +8 -5
- package/src/lower/numeric-intersection.ts +15 -0
- package/src/lower/platform.ts +25 -12
- package/src/lower/program.ts +6 -9
- package/src/lower/statements.ts +2 -10
- package/src/project.ts +1 -1
- package/src/report/index.ts +0 -2
- package/src/typescript/check.ts +2 -2
package/dist/fr.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/project.ts
|
|
4
4
|
import { existsSync, realpathSync } from "node:fs";
|
|
5
5
|
import { resolve as resolve3 } from "node:path";
|
|
6
|
-
import * as
|
|
6
|
+
import * as ts14 from "typescript";
|
|
7
7
|
|
|
8
8
|
// src/domain/number.ts
|
|
9
9
|
var float64Scratch = new Float64Array(1);
|
|
@@ -2975,17 +2975,18 @@ function reachableFrom(successors, start) {
|
|
|
2975
2975
|
}
|
|
2976
2976
|
|
|
2977
2977
|
// src/lower/program.ts
|
|
2978
|
-
import * as
|
|
2978
|
+
import * as ts10 from "typescript";
|
|
2979
2979
|
|
|
2980
2980
|
// src/lower/accept.ts
|
|
2981
2981
|
import * as ts from "typescript";
|
|
2982
2982
|
|
|
2983
2983
|
// src/lower/context.ts
|
|
2984
|
-
function createFunctionContext(sourceFile, checker, functionsBySymbol, moduleBindingsBySymbol, sites, staticAnnotations = [], returnsVoid = true) {
|
|
2984
|
+
function createFunctionContext(sourceFile, checker, program, functionsBySymbol, moduleBindingsBySymbol, sites, staticAnnotations = [], returnsVoid = true) {
|
|
2985
2985
|
const entry = { loopHeader: null, parameters: [], instructions: [], terminator: null };
|
|
2986
2986
|
return {
|
|
2987
2987
|
sourceFile,
|
|
2988
2988
|
checker,
|
|
2989
|
+
program,
|
|
2989
2990
|
functionsBySymbol,
|
|
2990
2991
|
moduleBindingsBySymbol,
|
|
2991
2992
|
staticAnnotations: new Map(staticAnnotations.map((annotation) => [annotation.call, annotation])),
|
|
@@ -3192,11 +3193,29 @@ function evalMention(sourceFile) {
|
|
|
3192
3193
|
}
|
|
3193
3194
|
|
|
3194
3195
|
// src/lower/expression.ts
|
|
3195
|
-
import * as
|
|
3196
|
+
import * as ts5 from "typescript";
|
|
3196
3197
|
|
|
3197
|
-
// src/lower/
|
|
3198
|
+
// src/lower/numeric-intersection.ts
|
|
3198
3199
|
import * as ts2 from "typescript";
|
|
3200
|
+
function numberConstituent(type) {
|
|
3201
|
+
if ((type.flags & ts2.TypeFlags.NumberLike) !== 0)
|
|
3202
|
+
return type;
|
|
3203
|
+
if (!type.isIntersection())
|
|
3204
|
+
return null;
|
|
3205
|
+
const numberTypes = type.types.filter((member) => (member.flags & ts2.TypeFlags.NumberLike) !== 0);
|
|
3206
|
+
if (numberTypes.length !== 1)
|
|
3207
|
+
return null;
|
|
3208
|
+
for (const member of type.types) {
|
|
3209
|
+
if (member !== numberTypes[0] && (member.flags & ts2.TypeFlags.Object) === 0)
|
|
3210
|
+
return null;
|
|
3211
|
+
}
|
|
3212
|
+
return numberTypes[0];
|
|
3213
|
+
}
|
|
3214
|
+
|
|
3215
|
+
// src/lower/platform.ts
|
|
3216
|
+
import * as ts3 from "typescript";
|
|
3199
3217
|
var anyFinite = { lower: -Number.MAX_VALUE, upper: Number.MAX_VALUE };
|
|
3218
|
+
var maximumDateTime = 8640000000000000;
|
|
3200
3219
|
var catalog = [
|
|
3201
3220
|
{ path: ["document", "documentElement", "clientWidth"], call: false, fact: { lower: 0, upper: Number.MAX_VALUE, integer: true } },
|
|
3202
3221
|
{ path: ["document", "documentElement", "clientHeight"], call: false, fact: { lower: 0, upper: Number.MAX_VALUE, integer: true } },
|
|
@@ -3207,26 +3226,32 @@ var catalog = [
|
|
|
3207
3226
|
{ path: ["document", "body", "scrollTop"], call: false, fact: { ...anyFinite, integer: false } },
|
|
3208
3227
|
{ path: ["document", "body", "scrollLeft"], call: false, fact: { ...anyFinite, integer: false } },
|
|
3209
3228
|
{ path: ["performance", "now"], call: true, fact: { lower: 0, upper: Number.MAX_VALUE, integer: false } },
|
|
3210
|
-
{ path: ["Date", "now"], call: true, fact: { lower:
|
|
3229
|
+
{ path: ["Date", "now"], call: true, fact: { lower: -maximumDateTime, upper: maximumDateTime, integer: true } },
|
|
3211
3230
|
{ path: ["Math", "random"], call: true, fact: { lower: 0, upper: 0.9999999999999999, integer: false } }
|
|
3212
3231
|
];
|
|
3213
|
-
function platformFact(expression, call, checker) {
|
|
3232
|
+
function platformFact(expression, call, checker, program) {
|
|
3214
3233
|
const parts = [];
|
|
3215
3234
|
let current = expression;
|
|
3216
|
-
while (
|
|
3235
|
+
while (ts3.isPropertyAccessExpression(current)) {
|
|
3217
3236
|
parts.unshift(current.name.text);
|
|
3218
3237
|
current = current.expression;
|
|
3219
3238
|
}
|
|
3220
|
-
if (!
|
|
3239
|
+
if (!ts3.isIdentifier(current))
|
|
3221
3240
|
return null;
|
|
3222
3241
|
parts.unshift(current.text);
|
|
3223
3242
|
const entry = catalog.find((candidate) => candidate.call === call && candidate.path.length === parts.length && candidate.path.every((segment, index) => segment === parts[index]));
|
|
3224
3243
|
if (entry == null)
|
|
3225
3244
|
return null;
|
|
3226
|
-
if (!
|
|
3245
|
+
if (!hasDefaultLibraryDeclaration(checker.getSymbolAtLocation(current), program))
|
|
3227
3246
|
return null;
|
|
3228
3247
|
return entry.fact;
|
|
3229
3248
|
}
|
|
3249
|
+
function hasDefaultLibraryDeclaration(symbol, program) {
|
|
3250
|
+
const declarations = symbol?.declarations;
|
|
3251
|
+
if (declarations == null || declarations.length === 0)
|
|
3252
|
+
return false;
|
|
3253
|
+
return declarations.some((declaration) => program.isSourceFileDefaultLibrary(declaration.getSourceFile()));
|
|
3254
|
+
}
|
|
3230
3255
|
function declaredOnlyInDeclarationFiles(symbol) {
|
|
3231
3256
|
const declarations = symbol?.declarations;
|
|
3232
3257
|
if (declarations == null || declarations.length === 0)
|
|
@@ -3235,16 +3260,16 @@ function declaredOnlyInDeclarationFiles(symbol) {
|
|
|
3235
3260
|
}
|
|
3236
3261
|
|
|
3237
3262
|
// src/lower/literals.ts
|
|
3238
|
-
import * as
|
|
3263
|
+
import * as ts4 from "typescript";
|
|
3239
3264
|
function numericLiteralValue(expression) {
|
|
3240
3265
|
const current = unwrapLiteral(expression);
|
|
3241
|
-
if (
|
|
3266
|
+
if (ts4.isNumericLiteral(current))
|
|
3242
3267
|
return Number(current.text);
|
|
3243
|
-
if (
|
|
3268
|
+
if (ts4.isPrefixUnaryExpression(current) && (current.operator === ts4.SyntaxKind.PlusToken || current.operator === ts4.SyntaxKind.MinusToken)) {
|
|
3244
3269
|
const operand = unwrapLiteral(current.operand);
|
|
3245
|
-
if (!
|
|
3270
|
+
if (!ts4.isNumericLiteral(operand))
|
|
3246
3271
|
return null;
|
|
3247
|
-
return Number(operand.text) * (current.operator ===
|
|
3272
|
+
return Number(operand.text) * (current.operator === ts4.SyntaxKind.MinusToken ? -1 : 1);
|
|
3248
3273
|
}
|
|
3249
3274
|
return null;
|
|
3250
3275
|
}
|
|
@@ -3253,13 +3278,13 @@ function parameterDefaultLiteral(initializer, checker) {
|
|
|
3253
3278
|
const number = numericLiteralValue(current);
|
|
3254
3279
|
if (number != null)
|
|
3255
3280
|
return Number.isFinite(number) ? { kind: "number", value: number } : null;
|
|
3256
|
-
if (current.kind ===
|
|
3257
|
-
return { kind: "boolean", value: current.kind ===
|
|
3281
|
+
if (current.kind === ts4.SyntaxKind.TrueKeyword || current.kind === ts4.SyntaxKind.FalseKeyword) {
|
|
3282
|
+
return { kind: "boolean", value: current.kind === ts4.SyntaxKind.TrueKeyword };
|
|
3258
3283
|
}
|
|
3259
|
-
if (
|
|
3284
|
+
if (ts4.isStringLiteral(current) || ts4.isNoSubstitutionTemplateLiteral(current)) {
|
|
3260
3285
|
return { kind: "opaque", content: current.text };
|
|
3261
3286
|
}
|
|
3262
|
-
if (current.kind ===
|
|
3287
|
+
if (current.kind === ts4.SyntaxKind.NullKeyword)
|
|
3263
3288
|
return { kind: "nullish", sentinel: "null" };
|
|
3264
3289
|
if (isUndefinedGlobal(current, checker)) {
|
|
3265
3290
|
return { kind: "nullish", sentinel: "undefined" };
|
|
@@ -3267,10 +3292,10 @@ function parameterDefaultLiteral(initializer, checker) {
|
|
|
3267
3292
|
return null;
|
|
3268
3293
|
}
|
|
3269
3294
|
function isUndefinedGlobal(expression, checker) {
|
|
3270
|
-
if (!
|
|
3295
|
+
if (!ts4.isIdentifier(expression) || expression.text !== "undefined")
|
|
3271
3296
|
return false;
|
|
3272
3297
|
const symbol = checker.getSymbolAtLocation(expression);
|
|
3273
|
-
const global = checker.resolveName("undefined", undefined,
|
|
3298
|
+
const global = checker.resolveName("undefined", undefined, ts4.SymbolFlags.Value, false);
|
|
3274
3299
|
return symbol != null && symbol === global;
|
|
3275
3300
|
}
|
|
3276
3301
|
function parameterDefaultFits(default_, declared) {
|
|
@@ -3299,7 +3324,7 @@ function parameterDefaultFits(default_, declared) {
|
|
|
3299
3324
|
}
|
|
3300
3325
|
function unwrapLiteral(expression) {
|
|
3301
3326
|
let current = expression;
|
|
3302
|
-
while (
|
|
3327
|
+
while (ts4.isParenthesizedExpression(current) || ts4.isAsExpression(current) || ts4.isTypeAssertionExpression(current))
|
|
3303
3328
|
current = current.expression;
|
|
3304
3329
|
return current;
|
|
3305
3330
|
}
|
|
@@ -3349,7 +3374,7 @@ function lowerStatementExpression(expression, context) {
|
|
|
3349
3374
|
return;
|
|
3350
3375
|
}
|
|
3351
3376
|
case "compound": {
|
|
3352
|
-
if (assignment.operator === "add" && (context.checker.getTypeAtLocation(current).flags &
|
|
3377
|
+
if (assignment.operator === "add" && (context.checker.getTypeAtLocation(current).flags & ts5.TypeFlags.StringLike) !== 0) {
|
|
3353
3378
|
lowerExpression(assignment.node.right, context);
|
|
3354
3379
|
const concatenated = addInstruction(context, current, { kind: "opaqueConstant" });
|
|
3355
3380
|
assignIdentifier(symbol, assignment.target, concatenated, current, context);
|
|
@@ -3368,7 +3393,7 @@ function lowerStatementExpression(expression, context) {
|
|
|
3368
3393
|
const one = addInstruction(context, current, { kind: "constant", value: 1 });
|
|
3369
3394
|
const value2 = addInstruction(context, current, {
|
|
3370
3395
|
kind: "binary",
|
|
3371
|
-
operator: assignment.node.operator ===
|
|
3396
|
+
operator: assignment.node.operator === ts5.SyntaxKind.PlusPlusToken ? "add" : "subtract",
|
|
3372
3397
|
left: previous,
|
|
3373
3398
|
right: one
|
|
3374
3399
|
});
|
|
@@ -3381,43 +3406,43 @@ function lowerStatementExpression(expression, context) {
|
|
|
3381
3406
|
}
|
|
3382
3407
|
function lowerExpression(expression, context) {
|
|
3383
3408
|
const current = unwrap(expression, context.checker);
|
|
3384
|
-
if (
|
|
3409
|
+
if (ts5.isNumericLiteral(current)) {
|
|
3385
3410
|
return addInstruction(context, current, { kind: "constant", value: Number(current.text) });
|
|
3386
3411
|
}
|
|
3387
|
-
if (current.kind ===
|
|
3388
|
-
return addInstruction(context, current, { kind: "booleanConstant", value: current.kind ===
|
|
3412
|
+
if (current.kind === ts5.SyntaxKind.TrueKeyword || current.kind === ts5.SyntaxKind.FalseKeyword) {
|
|
3413
|
+
return addInstruction(context, current, { kind: "booleanConstant", value: current.kind === ts5.SyntaxKind.TrueKeyword });
|
|
3389
3414
|
}
|
|
3390
|
-
if (
|
|
3415
|
+
if (ts5.isPrefixUnaryExpression(current) && current.operator === ts5.SyntaxKind.PlusToken) {
|
|
3391
3416
|
const positive = unwrap(current.operand, context.checker);
|
|
3392
|
-
if (
|
|
3417
|
+
if (ts5.isNumericLiteral(positive)) {
|
|
3393
3418
|
return addInstruction(context, current, { kind: "constant", value: Number(positive.text) });
|
|
3394
3419
|
}
|
|
3395
|
-
throw unsupported(current, { kind: "expressionForm", syntax:
|
|
3420
|
+
throw unsupported(current, { kind: "expressionForm", syntax: ts5.SyntaxKind[current.kind] });
|
|
3396
3421
|
}
|
|
3397
|
-
if (
|
|
3422
|
+
if (ts5.isPrefixUnaryExpression(current) && current.operator === ts5.SyntaxKind.MinusToken) {
|
|
3398
3423
|
const negated = unwrap(current.operand, context.checker);
|
|
3399
|
-
if (
|
|
3424
|
+
if (ts5.isNumericLiteral(negated)) {
|
|
3400
3425
|
return addInstruction(context, current, { kind: "constant", value: -Number(negated.text) });
|
|
3401
3426
|
}
|
|
3402
|
-
if (
|
|
3427
|
+
if (isStandardGlobal(negated, "Infinity", context)) {
|
|
3403
3428
|
return addInstruction(context, current, { kind: "constant", value: Number.NEGATIVE_INFINITY });
|
|
3404
3429
|
}
|
|
3405
3430
|
const zero = addInstruction(context, current, { kind: "constant", value: 0 });
|
|
3406
3431
|
const value2 = lowerExpression(current.operand, context);
|
|
3407
3432
|
return addInstruction(context, current, { kind: "binary", operator: "subtract", left: zero, right: value2 });
|
|
3408
3433
|
}
|
|
3409
|
-
if (
|
|
3434
|
+
if (ts5.isPrefixUnaryExpression(current) && current.operator === ts5.SyntaxKind.ExclamationToken) {
|
|
3410
3435
|
requireBooleanCondition(current.operand, context.checker);
|
|
3411
3436
|
const value2 = lowerExpression(current.operand, context);
|
|
3412
3437
|
return addInstruction(context, current, { kind: "not", value: value2 });
|
|
3413
3438
|
}
|
|
3414
|
-
if (
|
|
3439
|
+
if (ts5.isConditionalExpression(current)) {
|
|
3415
3440
|
return lowerConditionalExpression(current, context);
|
|
3416
3441
|
}
|
|
3417
|
-
if (
|
|
3442
|
+
if (ts5.isIdentifier(current)) {
|
|
3418
3443
|
return identifierValue(requiredSymbol(current, context.checker), current, context);
|
|
3419
3444
|
}
|
|
3420
|
-
if (
|
|
3445
|
+
if (ts5.isArrayLiteralExpression(current)) {
|
|
3421
3446
|
const literalType = context.checker.getTypeAtLocation(current);
|
|
3422
3447
|
const literalKind = valueKind(literalType, context.checker);
|
|
3423
3448
|
if (literalKind !== "array" && literalKind !== "tuple" && current.elements.length > 0) {
|
|
@@ -3425,23 +3450,23 @@ function lowerExpression(expression, context) {
|
|
|
3425
3450
|
}
|
|
3426
3451
|
const elements = [];
|
|
3427
3452
|
for (const element of current.elements) {
|
|
3428
|
-
if (
|
|
3429
|
-
throw unsupported(element, { kind: "expressionForm", syntax:
|
|
3453
|
+
if (ts5.isSpreadElement(element) || ts5.isOmittedExpression(element)) {
|
|
3454
|
+
throw unsupported(element, { kind: "expressionForm", syntax: ts5.SyntaxKind[element.kind] });
|
|
3430
3455
|
}
|
|
3431
3456
|
elements.push(lowerExpression(element, context));
|
|
3432
3457
|
}
|
|
3433
3458
|
return addInstruction(context, current, { kind: "arrayLiteral", elements, form: literalKind === "tuple" ? "tuple" : "array" });
|
|
3434
3459
|
}
|
|
3435
|
-
if (
|
|
3460
|
+
if (ts5.isNonNullExpression(current) && ts5.isElementAccessExpression(current.expression)) {
|
|
3436
3461
|
return lowerElementAccess(current.expression, true, context);
|
|
3437
3462
|
}
|
|
3438
|
-
if (
|
|
3463
|
+
if (ts5.isElementAccessExpression(current)) {
|
|
3439
3464
|
return lowerElementAccess(current, false, context);
|
|
3440
3465
|
}
|
|
3441
|
-
if (
|
|
3466
|
+
if (ts5.isObjectLiteralExpression(current)) {
|
|
3442
3467
|
const properties = new Map;
|
|
3443
3468
|
for (const property of current.properties) {
|
|
3444
|
-
if (
|
|
3469
|
+
if (ts5.isShorthandPropertyAssignment(property)) {
|
|
3445
3470
|
const symbol = context.checker.getShorthandAssignmentValueSymbol(property);
|
|
3446
3471
|
if (symbol == null)
|
|
3447
3472
|
throw unsupported(property, { kind: "missingSymbol" });
|
|
@@ -3451,21 +3476,21 @@ function lowerExpression(expression, context) {
|
|
|
3451
3476
|
});
|
|
3452
3477
|
continue;
|
|
3453
3478
|
}
|
|
3454
|
-
if (
|
|
3479
|
+
if (ts5.isPropertyAssignment(property)) {
|
|
3455
3480
|
const name = propertyName(property.name);
|
|
3456
3481
|
if (name === "__proto__")
|
|
3457
3482
|
throw unsupported(property, { kind: "protoProperty" });
|
|
3458
3483
|
properties.set(name, { name, value: lowerExpression(property.initializer, context) });
|
|
3459
3484
|
continue;
|
|
3460
3485
|
}
|
|
3461
|
-
if (
|
|
3486
|
+
if (ts5.isSpreadAssignment(property))
|
|
3462
3487
|
throw unsupported(property, { kind: "objectSpread" });
|
|
3463
3488
|
throw unsupported(property, { kind: "objectPropertyForm" });
|
|
3464
3489
|
}
|
|
3465
3490
|
const contextual = context.checker.getContextualType(current);
|
|
3466
3491
|
const fillOptionalsFrom = (recordType) => {
|
|
3467
3492
|
for (const member of context.checker.getPropertiesOfType(recordType)) {
|
|
3468
|
-
if ((member.flags &
|
|
3493
|
+
if ((member.flags & ts5.SymbolFlags.Optional) === 0 || properties.has(member.name))
|
|
3469
3494
|
continue;
|
|
3470
3495
|
const absent = addInstruction(context, current, { kind: "nullishConstant", sentinel: "undefined" });
|
|
3471
3496
|
properties.set(member.name, { name: member.name, value: absent });
|
|
@@ -3498,25 +3523,25 @@ function lowerExpression(expression, context) {
|
|
|
3498
3523
|
if (identifierAssignment(current) != null) {
|
|
3499
3524
|
throw unsupported(current, { kind: "assignmentInValuePosition" });
|
|
3500
3525
|
}
|
|
3501
|
-
if (
|
|
3526
|
+
if (ts5.isBinaryExpression(current) && (current.operatorToken.kind === ts5.SyntaxKind.AmpersandAmpersandToken || current.operatorToken.kind === ts5.SyntaxKind.BarBarToken)) {
|
|
3502
3527
|
return lowerLogicalExpression(current, context);
|
|
3503
3528
|
}
|
|
3504
|
-
if (current.kind ===
|
|
3529
|
+
if (current.kind === ts5.SyntaxKind.NullKeyword) {
|
|
3505
3530
|
return addInstruction(context, current, { kind: "nullishConstant", sentinel: "null" });
|
|
3506
3531
|
}
|
|
3507
|
-
if (
|
|
3532
|
+
if (ts5.isStringLiteral(current) || ts5.isNoSubstitutionTemplateLiteral(current)) {
|
|
3508
3533
|
return addInstruction(context, current, { kind: "opaqueConstant", content: current.text });
|
|
3509
3534
|
}
|
|
3510
|
-
if (
|
|
3535
|
+
if (ts5.isAsExpression(current) || ts5.isTypeAssertionExpression(current)) {
|
|
3511
3536
|
lowerExpression(current.expression, context);
|
|
3512
3537
|
return addInstruction(context, current, { kind: "opaqueConstant" });
|
|
3513
3538
|
}
|
|
3514
|
-
if (
|
|
3539
|
+
if (ts5.isTemplateExpression(current)) {
|
|
3515
3540
|
for (const span of current.templateSpans)
|
|
3516
3541
|
lowerExpression(span.expression, context);
|
|
3517
3542
|
return addInstruction(context, current, { kind: "opaqueConstant" });
|
|
3518
3543
|
}
|
|
3519
|
-
if (
|
|
3544
|
+
if (ts5.isBinaryExpression(current) && current.operatorToken.kind === ts5.SyntaxKind.QuestionQuestionToken) {
|
|
3520
3545
|
const resultType = context.checker.getTypeAtLocation(current);
|
|
3521
3546
|
if (valueKind(resultType, context.checker) == null) {
|
|
3522
3547
|
throw unsupported(current, { kind: "valueType", typeText: context.checker.typeToString(resultType) });
|
|
@@ -3525,11 +3550,11 @@ function lowerExpression(expression, context) {
|
|
|
3525
3550
|
const notMissing = addInstruction(context, current, { kind: "nullishCheck", value: left, sentinel: "nullish", negated: true });
|
|
3526
3551
|
return lowerValueBranch(current, notMissing, () => left, () => lowerExpression(current.right, context), context);
|
|
3527
3552
|
}
|
|
3528
|
-
if (
|
|
3553
|
+
if (ts5.isBinaryExpression(current)) {
|
|
3529
3554
|
const missingCheck = missingSentinelCheck(current, context);
|
|
3530
3555
|
if (missingCheck != null)
|
|
3531
3556
|
return missingCheck;
|
|
3532
|
-
if (current.operatorToken.kind ===
|
|
3557
|
+
if (current.operatorToken.kind === ts5.SyntaxKind.InstanceOfKeyword && ts5.isIdentifier(current.right) && declaredOnlyInDeclarationFiles(context.checker.getSymbolAtLocation(current.right))) {
|
|
3533
3558
|
lowerExpression(current.left, context);
|
|
3534
3559
|
return addInstruction(context, current, { kind: "unknownBoolean" });
|
|
3535
3560
|
}
|
|
@@ -3539,7 +3564,7 @@ function lowerExpression(expression, context) {
|
|
|
3539
3564
|
const opaqueComparison = opaqueEqualityCheck(current, context);
|
|
3540
3565
|
if (opaqueComparison != null)
|
|
3541
3566
|
return opaqueComparison;
|
|
3542
|
-
if (current.operatorToken.kind ===
|
|
3567
|
+
if (current.operatorToken.kind === ts5.SyntaxKind.PlusToken && (context.checker.getTypeAtLocation(current).flags & ts5.TypeFlags.StringLike) !== 0) {
|
|
3543
3568
|
lowerExpression(current.left, context);
|
|
3544
3569
|
lowerExpression(current.right, context);
|
|
3545
3570
|
return addInstruction(context, current, { kind: "opaqueConstant" });
|
|
@@ -3560,13 +3585,13 @@ function lowerExpression(expression, context) {
|
|
|
3560
3585
|
const right = lowerExpression(current.right, context);
|
|
3561
3586
|
return arithmetic != null ? addInstruction(context, current, { kind: "binary", operator: arithmetic, left, right }) : addInstruction(context, current, { kind: "compare", operator: comparison, left, right });
|
|
3562
3587
|
}
|
|
3563
|
-
if (
|
|
3588
|
+
if (ts5.isCallExpression(current)) {
|
|
3564
3589
|
const staticAnnotation = context.staticAnnotations.get(current);
|
|
3565
3590
|
if (staticAnnotation != null)
|
|
3566
3591
|
return lowerStaticAnnotation(staticAnnotation, context);
|
|
3567
|
-
if (
|
|
3592
|
+
if (ts5.isIdentifier(current.expression)) {
|
|
3568
3593
|
const globalName = current.expression.text;
|
|
3569
|
-
if ((globalName === "parseFloat" || globalName === "parseInt" || globalName === "Number") &&
|
|
3594
|
+
if ((globalName === "parseFloat" || globalName === "parseInt" || globalName === "Number") && isStandardGlobal(current.expression, globalName, context)) {
|
|
3570
3595
|
for (const argument of current.arguments)
|
|
3571
3596
|
lowerExpression(argument, context);
|
|
3572
3597
|
return addInstruction(context, current, { kind: "parsedNumber", integer: globalName === "parseInt" });
|
|
@@ -3592,7 +3617,7 @@ function lowerExpression(expression, context) {
|
|
|
3592
3617
|
continue;
|
|
3593
3618
|
}
|
|
3594
3619
|
const callableParameter = callee.signature?.declaration?.parameters[index];
|
|
3595
|
-
if (callableParameter != null &&
|
|
3620
|
+
if (callableParameter != null && ts5.isParameter(callableParameter) && callableParameter.questionToken != null) {
|
|
3596
3621
|
arguments_.push(addInstruction(context, parameter, { kind: "nullishConstant", sentinel: "undefined" }));
|
|
3597
3622
|
continue;
|
|
3598
3623
|
}
|
|
@@ -3619,13 +3644,13 @@ function lowerExpression(expression, context) {
|
|
|
3619
3644
|
binding: callee.binding
|
|
3620
3645
|
});
|
|
3621
3646
|
}
|
|
3622
|
-
if (
|
|
3623
|
-
const platformCall = current.arguments.length === 0 ? platformFact(current.expression, true, context.checker) : null;
|
|
3647
|
+
if (ts5.isPropertyAccessExpression(current.expression)) {
|
|
3648
|
+
const platformCall = current.arguments.length === 0 ? platformFact(current.expression, true, context.checker, context.program) : null;
|
|
3624
3649
|
if (platformCall != null) {
|
|
3625
3650
|
return addInstruction(context, current, { kind: "platformValue", ...platformCall });
|
|
3626
3651
|
}
|
|
3627
3652
|
const method = current.expression.name.text;
|
|
3628
|
-
const standardMath =
|
|
3653
|
+
const standardMath = isStandardGlobal(current.expression.expression, "Math", context);
|
|
3629
3654
|
if (standardMath && method === "floor" && current.arguments.length === 1) {
|
|
3630
3655
|
requireNumberType(current.arguments[0], context.checker);
|
|
3631
3656
|
const value2 = lowerExpression(current.arguments[0], context);
|
|
@@ -3647,7 +3672,7 @@ function lowerExpression(expression, context) {
|
|
|
3647
3672
|
const values = current.arguments.map((argument) => lowerExpression(argument, context));
|
|
3648
3673
|
return addInstruction(context, current, { kind: method === "min" ? "minimum" : "maximum", values });
|
|
3649
3674
|
}
|
|
3650
|
-
const standardNumber =
|
|
3675
|
+
const standardNumber = isStandardGlobal(current.expression.expression, "Number", context);
|
|
3651
3676
|
if (standardNumber && (method === "parseFloat" || method === "parseInt") && current.arguments.length >= 1) {
|
|
3652
3677
|
for (const argument of current.arguments)
|
|
3653
3678
|
lowerExpression(argument, context);
|
|
@@ -3662,7 +3687,7 @@ function lowerExpression(expression, context) {
|
|
|
3662
3687
|
value: value2
|
|
3663
3688
|
});
|
|
3664
3689
|
}
|
|
3665
|
-
const arrayMethod =
|
|
3690
|
+
const arrayMethod = ts5.isPropertyAccessExpression(current.expression) && context.checker.isArrayType(context.checker.getTypeAtLocation(current.expression.expression)) ? current.expression.name.text === "reduce" ? "reduce" : "other" : null;
|
|
3666
3691
|
throw unsupported(current, {
|
|
3667
3692
|
kind: "call",
|
|
3668
3693
|
callee: calleeDisplayName(current.expression, context.sourceFile),
|
|
@@ -3670,8 +3695,8 @@ function lowerExpression(expression, context) {
|
|
|
3670
3695
|
});
|
|
3671
3696
|
}
|
|
3672
3697
|
}
|
|
3673
|
-
if (
|
|
3674
|
-
const platform = platformFact(current, false, context.checker);
|
|
3698
|
+
if (ts5.isPropertyAccessExpression(current)) {
|
|
3699
|
+
const platform = platformFact(current, false, context.checker, context.program);
|
|
3675
3700
|
if (platform != null) {
|
|
3676
3701
|
return addInstruction(context, current, { kind: "platformValue", ...platform });
|
|
3677
3702
|
}
|
|
@@ -3689,12 +3714,12 @@ function lowerExpression(expression, context) {
|
|
|
3689
3714
|
const array = lowerExpression(current.expression, context);
|
|
3690
3715
|
return addInstruction(context, current, { kind: "arrayLength", array });
|
|
3691
3716
|
}
|
|
3692
|
-
if (receiverKind === "opaque" && current.name.text === "length" && (objectType.flags &
|
|
3717
|
+
if (receiverKind === "opaque" && current.name.text === "length" && (objectType.flags & ts5.TypeFlags.StringLike) !== 0) {
|
|
3693
3718
|
const value2 = lowerExpression(current.expression, context);
|
|
3694
3719
|
return addInstruction(context, current, { kind: "stringLength", value: value2 });
|
|
3695
3720
|
}
|
|
3696
|
-
const receiverSymbol =
|
|
3697
|
-
if (receiverSymbol != null && (receiverSymbol.flags & (
|
|
3721
|
+
const receiverSymbol = ts5.isIdentifier(current.expression) ? context.checker.getSymbolAtLocation(current.expression) : undefined;
|
|
3722
|
+
if (receiverSymbol != null && (receiverSymbol.flags & (ts5.SymbolFlags.RegularEnum | ts5.SymbolFlags.ConstEnum)) !== 0) {
|
|
3698
3723
|
throw unsupported(current, { kind: "enumMemberRead" });
|
|
3699
3724
|
}
|
|
3700
3725
|
if (receiverKind !== "object" && receiverKind !== "taggedUnion") {
|
|
@@ -3704,7 +3729,7 @@ function lowerExpression(expression, context) {
|
|
|
3704
3729
|
const object = lowerExpression(current.expression, context);
|
|
3705
3730
|
return addInstruction(context, current, { kind: "property", object, property: current.name.text });
|
|
3706
3731
|
}
|
|
3707
|
-
throw unsupported(current, { kind: "expressionForm", syntax:
|
|
3732
|
+
throw unsupported(current, { kind: "expressionForm", syntax: ts5.SyntaxKind[current.kind] });
|
|
3708
3733
|
}
|
|
3709
3734
|
function lowerStaticAnnotation(annotation, context) {
|
|
3710
3735
|
if (annotation.kind === "invalid") {
|
|
@@ -3721,15 +3746,15 @@ function lowerStaticAnnotation(annotation, context) {
|
|
|
3721
3746
|
if (requirement == null) {
|
|
3722
3747
|
throw unsupported(condition, {
|
|
3723
3748
|
kind: "staticAssertionForm",
|
|
3724
|
-
problem: staticAssertionProblem(condition, context
|
|
3749
|
+
problem: staticAssertionProblem(condition, context, "callerRequirement")
|
|
3725
3750
|
});
|
|
3726
3751
|
}
|
|
3727
3752
|
value2 = lowerWrittenRequirement(requirement, condition, context);
|
|
3728
3753
|
} else {
|
|
3729
|
-
if (!supportedWrittenAssertion(condition, context
|
|
3754
|
+
if (!supportedWrittenAssertion(condition, context)) {
|
|
3730
3755
|
throw unsupported(condition, {
|
|
3731
3756
|
kind: "staticAssertionForm",
|
|
3732
|
-
problem: staticAssertionProblem(condition, context
|
|
3757
|
+
problem: staticAssertionProblem(condition, context, "directCheck")
|
|
3733
3758
|
});
|
|
3734
3759
|
}
|
|
3735
3760
|
value2 = lowerExpression(condition, context);
|
|
@@ -3751,7 +3776,7 @@ function lowerStaticAnnotation(annotation, context) {
|
|
|
3751
3776
|
}
|
|
3752
3777
|
function writtenRequirement(condition, context) {
|
|
3753
3778
|
const current = unwrapParentheses(condition);
|
|
3754
|
-
if (
|
|
3779
|
+
if (ts5.isCallExpression(current) && current.questionDotToken == null && current.arguments.length === 1 && ts5.isPropertyAccessExpression(current.expression) && current.expression.questionDotToken == null && isStandardGlobal(current.expression.expression, "Number", context) && (current.expression.name.text === "isInteger" || current.expression.name.text === "isFinite")) {
|
|
3755
3780
|
const argument = current.arguments[0];
|
|
3756
3781
|
const value2 = staticRequirementParameterPathValue(argument, context);
|
|
3757
3782
|
return value2 == null ? null : {
|
|
@@ -3760,7 +3785,7 @@ function writtenRequirement(condition, context) {
|
|
|
3760
3785
|
value: value2
|
|
3761
3786
|
};
|
|
3762
3787
|
}
|
|
3763
|
-
if (!
|
|
3788
|
+
if (!ts5.isBinaryExpression(current) || !staticAssertionComparison(current.operatorToken.kind))
|
|
3764
3789
|
return null;
|
|
3765
3790
|
const leftParameter = staticRequirementParameterPathValue(current.left, context);
|
|
3766
3791
|
const rightParameter = staticRequirementParameterPathValue(current.right, context);
|
|
@@ -3776,10 +3801,10 @@ function writtenRequirement(condition, context) {
|
|
|
3776
3801
|
function staticRequirementParameterPathValue(expression, context) {
|
|
3777
3802
|
requireNumberType(expression, context.checker);
|
|
3778
3803
|
let root = unwrapParentheses(expression);
|
|
3779
|
-
while (
|
|
3804
|
+
while (ts5.isPropertyAccessExpression(root) && root.questionDotToken == null) {
|
|
3780
3805
|
root = unwrapParentheses(root.expression);
|
|
3781
3806
|
}
|
|
3782
|
-
if (!
|
|
3807
|
+
if (!ts5.isIdentifier(root))
|
|
3783
3808
|
return null;
|
|
3784
3809
|
const symbol = context.checker.getSymbolAtLocation(root);
|
|
3785
3810
|
const rootValue = symbol == null ? null : context.bindings.get(symbol);
|
|
@@ -3806,14 +3831,14 @@ function staticFiniteValue(expression, context) {
|
|
|
3806
3831
|
if (literal != null)
|
|
3807
3832
|
return Number.isFinite(literal) ? literal : null;
|
|
3808
3833
|
const unwrapped = unwrapParentheses(current);
|
|
3809
|
-
if (!
|
|
3834
|
+
if (!ts5.isIdentifier(unwrapped))
|
|
3810
3835
|
return null;
|
|
3811
3836
|
const symbol = resolvedSymbol(context.checker.getSymbolAtLocation(unwrapped), context.checker);
|
|
3812
3837
|
if (symbol == null || seen.has(symbol))
|
|
3813
3838
|
return null;
|
|
3814
3839
|
seen.add(symbol);
|
|
3815
3840
|
const declaration = symbol.valueDeclaration;
|
|
3816
|
-
if (declaration == null || !
|
|
3841
|
+
if (declaration == null || !ts5.isVariableDeclaration(declaration) || (ts5.getCombinedNodeFlags(declaration) & ts5.NodeFlags.Const) === 0 || declaration.getSourceFile().isDeclarationFile || declaration.initializer == null)
|
|
3817
3842
|
return null;
|
|
3818
3843
|
current = declaration.initializer;
|
|
3819
3844
|
}
|
|
@@ -3838,25 +3863,25 @@ function lowerWrittenRequirement(requirement, condition, context) {
|
|
|
3838
3863
|
right: lowerOperand(requirement.right)
|
|
3839
3864
|
});
|
|
3840
3865
|
}
|
|
3841
|
-
function supportedWrittenAssertion(condition,
|
|
3866
|
+
function supportedWrittenAssertion(condition, context) {
|
|
3842
3867
|
const current = unwrapParentheses(condition);
|
|
3843
|
-
if (
|
|
3844
|
-
return staticAssertionNumericAtom(current.left, checker) && staticAssertionNumericAtom(current.right, checker);
|
|
3868
|
+
if (ts5.isBinaryExpression(current) && staticAssertionComparison(current.operatorToken.kind)) {
|
|
3869
|
+
return staticAssertionNumericAtom(current.left, context.checker) && staticAssertionNumericAtom(current.right, context.checker);
|
|
3845
3870
|
}
|
|
3846
|
-
const operand = staticNumberCheckOperand(current,
|
|
3847
|
-
return operand != null && staticAssertionNumericAtom(operand, checker);
|
|
3871
|
+
const operand = staticNumberCheckOperand(current, context);
|
|
3872
|
+
return operand != null && staticAssertionNumericAtom(operand, context.checker);
|
|
3848
3873
|
}
|
|
3849
3874
|
function staticAssertionNumericAtom(expression, checker) {
|
|
3850
3875
|
return staticAssertionAtom(expression) && valueKind(checker.getTypeAtLocation(expression), checker) === "number";
|
|
3851
3876
|
}
|
|
3852
3877
|
function staticAssertionComparison(kind) {
|
|
3853
3878
|
switch (kind) {
|
|
3854
|
-
case
|
|
3855
|
-
case
|
|
3856
|
-
case
|
|
3857
|
-
case
|
|
3858
|
-
case
|
|
3859
|
-
case
|
|
3879
|
+
case ts5.SyntaxKind.LessThanToken:
|
|
3880
|
+
case ts5.SyntaxKind.LessThanEqualsToken:
|
|
3881
|
+
case ts5.SyntaxKind.GreaterThanToken:
|
|
3882
|
+
case ts5.SyntaxKind.GreaterThanEqualsToken:
|
|
3883
|
+
case ts5.SyntaxKind.EqualsEqualsEqualsToken:
|
|
3884
|
+
case ts5.SyntaxKind.ExclamationEqualsEqualsToken:
|
|
3860
3885
|
return true;
|
|
3861
3886
|
default:
|
|
3862
3887
|
return false;
|
|
@@ -3864,54 +3889,54 @@ function staticAssertionComparison(kind) {
|
|
|
3864
3889
|
}
|
|
3865
3890
|
function staticAssertionAtomProblem(expression) {
|
|
3866
3891
|
const current = unwrapParentheses(expression);
|
|
3867
|
-
if (
|
|
3892
|
+
if (ts5.isIdentifier(current) || ts5.isNumericLiteral(current))
|
|
3868
3893
|
return null;
|
|
3869
|
-
if (
|
|
3870
|
-
return
|
|
3894
|
+
if (ts5.isPrefixUnaryExpression(current) && (current.operator === ts5.SyntaxKind.PlusToken || current.operator === ts5.SyntaxKind.MinusToken)) {
|
|
3895
|
+
return ts5.isNumericLiteral(unwrapParentheses(current.operand)) ? null : "bindValueFirst";
|
|
3871
3896
|
}
|
|
3872
|
-
if (
|
|
3897
|
+
if (ts5.isElementAccessExpression(current))
|
|
3873
3898
|
return "bindValueFirst";
|
|
3874
|
-
if (
|
|
3899
|
+
if (ts5.isNonNullExpression(current))
|
|
3875
3900
|
return staticAssertionAtomProblem(current.expression);
|
|
3876
|
-
if (
|
|
3901
|
+
if (ts5.isCallExpression(current))
|
|
3877
3902
|
return "functionCall";
|
|
3878
|
-
if (
|
|
3903
|
+
if (ts5.isBinaryExpression(current))
|
|
3879
3904
|
return "bindValueFirst";
|
|
3880
|
-
if (
|
|
3905
|
+
if (ts5.isPropertyAccessExpression(current)) {
|
|
3881
3906
|
return current.questionDotToken == null ? staticAssertionAtomProblem(current.expression) : "directCheck";
|
|
3882
3907
|
}
|
|
3883
3908
|
return "directCheck";
|
|
3884
3909
|
}
|
|
3885
3910
|
function staticAssertionAtom(expression) {
|
|
3886
3911
|
const current = unwrapParentheses(expression);
|
|
3887
|
-
if (
|
|
3912
|
+
if (ts5.isIdentifier(current) || ts5.isNumericLiteral(current))
|
|
3888
3913
|
return true;
|
|
3889
|
-
if (
|
|
3890
|
-
return
|
|
3914
|
+
if (ts5.isPrefixUnaryExpression(current) && (current.operator === ts5.SyntaxKind.PlusToken || current.operator === ts5.SyntaxKind.MinusToken)) {
|
|
3915
|
+
return ts5.isNumericLiteral(unwrapParentheses(current.operand));
|
|
3891
3916
|
}
|
|
3892
|
-
return
|
|
3917
|
+
return ts5.isPropertyAccessExpression(current) && current.questionDotToken == null && staticAssertionAtom(current.expression);
|
|
3893
3918
|
}
|
|
3894
|
-
function staticAssertionProblem(condition,
|
|
3919
|
+
function staticAssertionProblem(condition, context, fallback) {
|
|
3895
3920
|
const current = unwrapParentheses(condition);
|
|
3896
|
-
if (
|
|
3921
|
+
if (ts5.isBinaryExpression(current) && staticAssertionComparison(current.operatorToken.kind)) {
|
|
3897
3922
|
return staticAssertionAtomProblem(current.left) ?? staticAssertionAtomProblem(current.right) ?? fallback;
|
|
3898
3923
|
}
|
|
3899
|
-
const operand = staticNumberCheckOperand(current,
|
|
3924
|
+
const operand = staticNumberCheckOperand(current, context);
|
|
3900
3925
|
if (operand != null)
|
|
3901
3926
|
return staticAssertionAtomProblem(operand) ?? fallback;
|
|
3902
|
-
if (
|
|
3927
|
+
if (ts5.isCallExpression(current))
|
|
3903
3928
|
return "functionCall";
|
|
3904
3929
|
return "directCheck";
|
|
3905
3930
|
}
|
|
3906
|
-
function staticNumberCheckOperand(expression,
|
|
3907
|
-
if (!
|
|
3931
|
+
function staticNumberCheckOperand(expression, context) {
|
|
3932
|
+
if (!ts5.isCallExpression(expression) || expression.questionDotToken != null || expression.arguments.length !== 1 || !ts5.isPropertyAccessExpression(expression.expression) || expression.expression.questionDotToken != null)
|
|
3908
3933
|
return null;
|
|
3909
3934
|
const callee = expression.expression;
|
|
3910
|
-
return
|
|
3935
|
+
return isStandardGlobal(callee.expression, "Number", context) && (callee.name.text === "isInteger" || callee.name.text === "isFinite" || callee.name.text === "isNaN") ? expression.arguments[0] : null;
|
|
3911
3936
|
}
|
|
3912
3937
|
function unwrapParentheses(expression) {
|
|
3913
3938
|
let current = expression;
|
|
3914
|
-
while (
|
|
3939
|
+
while (ts5.isParenthesizedExpression(current))
|
|
3915
3940
|
current = current.expression;
|
|
3916
3941
|
return current;
|
|
3917
3942
|
}
|
|
@@ -3930,30 +3955,30 @@ function removableStaticConditionInstruction(instruction) {
|
|
|
3930
3955
|
}
|
|
3931
3956
|
}
|
|
3932
3957
|
function identifierAssignment(node) {
|
|
3933
|
-
if (
|
|
3934
|
-
if (node.operatorToken.kind ===
|
|
3958
|
+
if (ts5.isBinaryExpression(node) && ts5.isIdentifier(node.left)) {
|
|
3959
|
+
if (node.operatorToken.kind === ts5.SyntaxKind.EqualsToken)
|
|
3935
3960
|
return { form: "assign", target: node.left, node };
|
|
3936
3961
|
const operator = compoundAssignmentOperator(node.operatorToken.kind);
|
|
3937
3962
|
if (operator != null)
|
|
3938
3963
|
return { form: "compound", target: node.left, node, operator };
|
|
3939
|
-
const logical = node.operatorToken.kind ===
|
|
3964
|
+
const logical = node.operatorToken.kind === ts5.SyntaxKind.QuestionQuestionEqualsToken ? "nullish" : node.operatorToken.kind === ts5.SyntaxKind.BarBarEqualsToken ? "or" : node.operatorToken.kind === ts5.SyntaxKind.AmpersandAmpersandEqualsToken ? "and" : null;
|
|
3940
3965
|
if (logical != null)
|
|
3941
3966
|
return { form: "logical", target: node.left, node, logical };
|
|
3942
3967
|
}
|
|
3943
|
-
if ((
|
|
3968
|
+
if ((ts5.isPrefixUnaryExpression(node) || ts5.isPostfixUnaryExpression(node)) && (node.operator === ts5.SyntaxKind.PlusPlusToken || node.operator === ts5.SyntaxKind.MinusMinusToken) && ts5.isIdentifier(node.operand)) {
|
|
3944
3969
|
return { form: "update", target: node.operand, node };
|
|
3945
3970
|
}
|
|
3946
3971
|
return null;
|
|
3947
3972
|
}
|
|
3948
3973
|
function compoundAssignmentOperator(kind) {
|
|
3949
3974
|
switch (kind) {
|
|
3950
|
-
case
|
|
3975
|
+
case ts5.SyntaxKind.PlusEqualsToken:
|
|
3951
3976
|
return "add";
|
|
3952
|
-
case
|
|
3977
|
+
case ts5.SyntaxKind.MinusEqualsToken:
|
|
3953
3978
|
return "subtract";
|
|
3954
|
-
case
|
|
3979
|
+
case ts5.SyntaxKind.AsteriskEqualsToken:
|
|
3955
3980
|
return "multiply";
|
|
3956
|
-
case
|
|
3981
|
+
case ts5.SyntaxKind.SlashEqualsToken:
|
|
3957
3982
|
return "divide";
|
|
3958
3983
|
default:
|
|
3959
3984
|
return null;
|
|
@@ -4008,8 +4033,8 @@ function lowerConditionalExpression(expression, context) {
|
|
|
4008
4033
|
}
|
|
4009
4034
|
function lowerBranchingCondition(expression, whenTrue, whenFalse, context) {
|
|
4010
4035
|
const current = unwrap(expression, context.checker);
|
|
4011
|
-
if (
|
|
4012
|
-
const isAnd = current.operatorToken.kind ===
|
|
4036
|
+
if (ts5.isBinaryExpression(current) && (current.operatorToken.kind === ts5.SyntaxKind.AmpersandAmpersandToken || current.operatorToken.kind === ts5.SyntaxKind.BarBarToken)) {
|
|
4037
|
+
const isAnd = current.operatorToken.kind === ts5.SyntaxKind.AmpersandAmpersandToken;
|
|
4013
4038
|
const middle = createBlock(context);
|
|
4014
4039
|
if (isAnd) {
|
|
4015
4040
|
lowerBranchingCondition(current.left, middle, whenFalse, context);
|
|
@@ -4020,7 +4045,7 @@ function lowerBranchingCondition(expression, whenTrue, whenFalse, context) {
|
|
|
4020
4045
|
lowerBranchingCondition(current.right, whenTrue, whenFalse, context);
|
|
4021
4046
|
return;
|
|
4022
4047
|
}
|
|
4023
|
-
if (
|
|
4048
|
+
if (ts5.isPrefixUnaryExpression(current) && current.operator === ts5.SyntaxKind.ExclamationToken) {
|
|
4024
4049
|
lowerBranchingCondition(current.operand, whenFalse, whenTrue, context);
|
|
4025
4050
|
return;
|
|
4026
4051
|
}
|
|
@@ -4038,20 +4063,20 @@ function lowerBranchingCondition(expression, whenTrue, whenFalse, context) {
|
|
|
4038
4063
|
function lowerLogicalExpression(expression, context) {
|
|
4039
4064
|
requireBooleanCondition(expression.left, context.checker);
|
|
4040
4065
|
requireBooleanCondition(expression.right, context.checker);
|
|
4041
|
-
const isAnd = expression.operatorToken.kind ===
|
|
4066
|
+
const isAnd = expression.operatorToken.kind === ts5.SyntaxKind.AmpersandAmpersandToken;
|
|
4042
4067
|
return lowerBranchingValue(expression, expression.left, () => isAnd ? lowerExpression(expression.right, context) : addInstruction(context, expression, { kind: "booleanConstant", value: true }), () => isAnd ? addInstruction(context, expression, { kind: "booleanConstant", value: false }) : lowerExpression(expression.right, context), context);
|
|
4043
4068
|
}
|
|
4044
4069
|
function arithmeticOperator(kind) {
|
|
4045
4070
|
switch (kind) {
|
|
4046
|
-
case
|
|
4071
|
+
case ts5.SyntaxKind.PlusToken:
|
|
4047
4072
|
return "add";
|
|
4048
|
-
case
|
|
4073
|
+
case ts5.SyntaxKind.MinusToken:
|
|
4049
4074
|
return "subtract";
|
|
4050
|
-
case
|
|
4075
|
+
case ts5.SyntaxKind.AsteriskToken:
|
|
4051
4076
|
return "multiply";
|
|
4052
|
-
case
|
|
4077
|
+
case ts5.SyntaxKind.SlashToken:
|
|
4053
4078
|
return "divide";
|
|
4054
|
-
case
|
|
4079
|
+
case ts5.SyntaxKind.PercentToken:
|
|
4055
4080
|
return "remainder";
|
|
4056
4081
|
default:
|
|
4057
4082
|
return null;
|
|
@@ -4059,19 +4084,19 @@ function arithmeticOperator(kind) {
|
|
|
4059
4084
|
}
|
|
4060
4085
|
function comparisonOperator(kind) {
|
|
4061
4086
|
switch (kind) {
|
|
4062
|
-
case
|
|
4087
|
+
case ts5.SyntaxKind.LessThanToken:
|
|
4063
4088
|
return "lessThan";
|
|
4064
|
-
case
|
|
4089
|
+
case ts5.SyntaxKind.LessThanEqualsToken:
|
|
4065
4090
|
return "lessThanOrEqual";
|
|
4066
|
-
case
|
|
4091
|
+
case ts5.SyntaxKind.GreaterThanToken:
|
|
4067
4092
|
return "greaterThan";
|
|
4068
|
-
case
|
|
4093
|
+
case ts5.SyntaxKind.GreaterThanEqualsToken:
|
|
4069
4094
|
return "greaterThanOrEqual";
|
|
4070
|
-
case
|
|
4071
|
-
case
|
|
4095
|
+
case ts5.SyntaxKind.EqualsEqualsToken:
|
|
4096
|
+
case ts5.SyntaxKind.EqualsEqualsEqualsToken:
|
|
4072
4097
|
return "equal";
|
|
4073
|
-
case
|
|
4074
|
-
case
|
|
4098
|
+
case ts5.SyntaxKind.ExclamationEqualsToken:
|
|
4099
|
+
case ts5.SyntaxKind.ExclamationEqualsEqualsToken:
|
|
4075
4100
|
return "notEqual";
|
|
4076
4101
|
default:
|
|
4077
4102
|
return null;
|
|
@@ -4079,12 +4104,12 @@ function comparisonOperator(kind) {
|
|
|
4079
4104
|
}
|
|
4080
4105
|
function requireNumberType(node, checker) {
|
|
4081
4106
|
const type = checker.getTypeAtLocation(node);
|
|
4082
|
-
if (valueKind(type, checker) !== "number" && (type.flags &
|
|
4107
|
+
if (valueKind(type, checker) !== "number" && (type.flags & ts5.TypeFlags.Any) === 0) {
|
|
4083
4108
|
throw unsupported(node, { kind: "nonNumberOperand", typeText: checker.typeToString(type) });
|
|
4084
4109
|
}
|
|
4085
4110
|
}
|
|
4086
4111
|
function typeCanIncludeUndefined(type) {
|
|
4087
|
-
if ((type.flags & (
|
|
4112
|
+
if ((type.flags & (ts5.TypeFlags.Undefined | ts5.TypeFlags.Any | ts5.TypeFlags.Unknown)) !== 0)
|
|
4088
4113
|
return true;
|
|
4089
4114
|
return type.isUnion() && type.types.some(typeCanIncludeUndefined);
|
|
4090
4115
|
}
|
|
@@ -4117,19 +4142,19 @@ function valueKind(type, checker, depth = 0) {
|
|
|
4117
4142
|
return result;
|
|
4118
4143
|
}
|
|
4119
4144
|
function valueKindUncached(type, checker, depth) {
|
|
4120
|
-
if ((type
|
|
4145
|
+
if (numberConstituent(type) != null)
|
|
4121
4146
|
return "number";
|
|
4122
|
-
if ((type.flags &
|
|
4147
|
+
if ((type.flags & ts5.TypeFlags.BooleanLike) !== 0)
|
|
4123
4148
|
return "boolean";
|
|
4124
|
-
if ((type.flags &
|
|
4149
|
+
if ((type.flags & ts5.TypeFlags.StringLike) !== 0)
|
|
4125
4150
|
return "opaque";
|
|
4126
4151
|
if (checker.isTupleType(type))
|
|
4127
4152
|
return "tuple";
|
|
4128
4153
|
if (checker.isArrayType(type)) {
|
|
4129
|
-
const element = checker.getIndexTypeOfType(type,
|
|
4154
|
+
const element = checker.getIndexTypeOfType(type, ts5.IndexKind.Number);
|
|
4130
4155
|
return element != null && valueKind(element, checker, depth + 1) != null ? "array" : null;
|
|
4131
4156
|
}
|
|
4132
|
-
const objectLike = (type.flags &
|
|
4157
|
+
const objectLike = (type.flags & ts5.TypeFlags.Object) !== 0 || type.isIntersection() && type.types.every((member) => valueKind(member, checker, depth + 1) === "object");
|
|
4133
4158
|
if (objectLike) {
|
|
4134
4159
|
if (checker.getIndexInfosOfType(type).length > 0)
|
|
4135
4160
|
return null;
|
|
@@ -4140,10 +4165,10 @@ function valueKindUncached(type, checker, depth) {
|
|
|
4140
4165
|
const anchored = checker.getPropertiesOfType(type).some((property) => checker.getTypeOfSymbol(property).getCallSignatures().length === 0);
|
|
4141
4166
|
return anchored ? "object" : null;
|
|
4142
4167
|
}
|
|
4143
|
-
if ((type.flags & (
|
|
4168
|
+
if ((type.flags & (ts5.TypeFlags.Unknown | ts5.TypeFlags.Any)) !== 0)
|
|
4144
4169
|
return "opaque";
|
|
4145
4170
|
if (type.isUnion()) {
|
|
4146
|
-
const missingFlags =
|
|
4171
|
+
const missingFlags = ts5.TypeFlags.Null | ts5.TypeFlags.Undefined;
|
|
4147
4172
|
if (type.types.some((member) => (member.flags & missingFlags) !== 0)) {
|
|
4148
4173
|
const rest = nonMissingUnionMembers(type);
|
|
4149
4174
|
const restKind = classifyUnionMembers(rest, checker, depth + 1);
|
|
@@ -4162,7 +4187,7 @@ function nonMissingUnionMembers(type) {
|
|
|
4162
4187
|
const cached = nonMissingUnionMembersCache.get(type);
|
|
4163
4188
|
if (cached != null)
|
|
4164
4189
|
return cached;
|
|
4165
|
-
const missingFlags =
|
|
4190
|
+
const missingFlags = ts5.TypeFlags.Null | ts5.TypeFlags.Undefined;
|
|
4166
4191
|
const members = type.types.filter((member) => (member.flags & missingFlags) === 0);
|
|
4167
4192
|
nonMissingUnionMembersCache.set(type, members);
|
|
4168
4193
|
return members;
|
|
@@ -4192,7 +4217,7 @@ function taggedUnionPropertyUncached(members, checker, depth) {
|
|
|
4192
4217
|
const qualifies = (candidateName, singleLiteralOnly) => {
|
|
4193
4218
|
for (const member of members) {
|
|
4194
4219
|
const property = checker.getPropertyOfType(member, candidateName);
|
|
4195
|
-
if (property == null || (property.flags &
|
|
4220
|
+
if (property == null || (property.flags & ts5.SymbolFlags.Optional) !== 0)
|
|
4196
4221
|
return false;
|
|
4197
4222
|
const literals = tagLiteralValues(checker.getTypeOfSymbol(property));
|
|
4198
4223
|
if (literals == null || singleLiteralOnly && literals.length !== 1)
|
|
@@ -4202,7 +4227,7 @@ function taggedUnionPropertyUncached(members, checker, depth) {
|
|
|
4202
4227
|
};
|
|
4203
4228
|
for (const singleLiteralOnly of [true, false]) {
|
|
4204
4229
|
for (const candidate of checker.getPropertiesOfType(first)) {
|
|
4205
|
-
if ((candidate.flags &
|
|
4230
|
+
if ((candidate.flags & ts5.SymbolFlags.Optional) !== 0)
|
|
4206
4231
|
continue;
|
|
4207
4232
|
if (qualifies(candidate.name, singleLiteralOnly))
|
|
4208
4233
|
return candidate.name;
|
|
@@ -4211,28 +4236,28 @@ function taggedUnionPropertyUncached(members, checker, depth) {
|
|
|
4211
4236
|
return null;
|
|
4212
4237
|
}
|
|
4213
4238
|
function calleeDisplayName(expression, sourceFile) {
|
|
4214
|
-
if (
|
|
4239
|
+
if (ts5.isPropertyAccessExpression(expression)) {
|
|
4215
4240
|
const receiver = expression.expression;
|
|
4216
|
-
const receiverName =
|
|
4241
|
+
const receiverName = ts5.isIdentifier(receiver) ? receiver.text : ts5.isPropertyAccessExpression(receiver) && ts5.isIdentifier(receiver.expression) ? `${receiver.expression.text}.${receiver.name.text}` : "(…)";
|
|
4217
4242
|
return `${receiverName}.${expression.name.text}`;
|
|
4218
4243
|
}
|
|
4219
4244
|
return expression.getText(sourceFile).replace(/\s+/g, " ").slice(0, 60);
|
|
4220
4245
|
}
|
|
4221
4246
|
function writtenTagLiteral(literal, tagProperty, context) {
|
|
4222
|
-
if (!
|
|
4247
|
+
if (!ts5.isObjectLiteralExpression(literal))
|
|
4223
4248
|
return null;
|
|
4224
4249
|
for (const property of literal.properties) {
|
|
4225
|
-
if (!
|
|
4250
|
+
if (!ts5.isPropertyAssignment(property))
|
|
4226
4251
|
continue;
|
|
4227
|
-
const name =
|
|
4252
|
+
const name = ts5.isIdentifier(property.name) || ts5.isStringLiteral(property.name) ? property.name.text : null;
|
|
4228
4253
|
if (name !== tagProperty)
|
|
4229
4254
|
continue;
|
|
4230
4255
|
const initializer = unwrap(property.initializer, context.checker);
|
|
4231
|
-
if (
|
|
4256
|
+
if (ts5.isStringLiteral(initializer) || ts5.isNoSubstitutionTemplateLiteral(initializer))
|
|
4232
4257
|
return initializer.text;
|
|
4233
|
-
if (initializer.kind ===
|
|
4258
|
+
if (initializer.kind === ts5.SyntaxKind.TrueKeyword)
|
|
4234
4259
|
return true;
|
|
4235
|
-
if (initializer.kind ===
|
|
4260
|
+
if (initializer.kind === ts5.SyntaxKind.FalseKeyword)
|
|
4236
4261
|
return false;
|
|
4237
4262
|
return null;
|
|
4238
4263
|
}
|
|
@@ -4242,7 +4267,7 @@ function tagLiteralValues(type) {
|
|
|
4242
4267
|
const single = (member) => {
|
|
4243
4268
|
if (member.isStringLiteral())
|
|
4244
4269
|
return member.value;
|
|
4245
|
-
if ((member.flags &
|
|
4270
|
+
if ((member.flags & ts5.TypeFlags.BooleanLiteral) !== 0) {
|
|
4246
4271
|
return member.intrinsicName === "true";
|
|
4247
4272
|
}
|
|
4248
4273
|
return null;
|
|
@@ -4289,10 +4314,10 @@ function structuralTypeWalkCompletes(type, checker, seen) {
|
|
|
4289
4314
|
if (checker.isArrayType(type)) {
|
|
4290
4315
|
if (seen.length >= 8 || seen.includes(type))
|
|
4291
4316
|
return false;
|
|
4292
|
-
const element = checker.getIndexTypeOfType(type,
|
|
4317
|
+
const element = checker.getIndexTypeOfType(type, ts5.IndexKind.Number);
|
|
4293
4318
|
return element == null || structuralTypeWalkCompletes(element, checker, [...seen, type]);
|
|
4294
4319
|
}
|
|
4295
|
-
if ((type.flags &
|
|
4320
|
+
if ((type.flags & ts5.TypeFlags.Object) === 0)
|
|
4296
4321
|
return true;
|
|
4297
4322
|
if (seen.length >= 8 || seen.includes(type))
|
|
4298
4323
|
return false;
|
|
@@ -4307,7 +4332,7 @@ function structuralTypeWalkCompletes(type, checker, seen) {
|
|
|
4307
4332
|
function structuralPropertiesComplete(type, checker, seen) {
|
|
4308
4333
|
const nextSeen = [...seen, type];
|
|
4309
4334
|
for (const property of checker.getPropertiesOfType(type)) {
|
|
4310
|
-
if ((property.flags &
|
|
4335
|
+
if ((property.flags & ts5.SymbolFlags.Optional) !== 0)
|
|
4311
4336
|
continue;
|
|
4312
4337
|
if (!structuralTypeWalkCompletes(checker.getTypeOfSymbol(property), checker, nextSeen))
|
|
4313
4338
|
return false;
|
|
@@ -4326,12 +4351,6 @@ function requireBooleanCondition(node, checker) {
|
|
|
4326
4351
|
});
|
|
4327
4352
|
}
|
|
4328
4353
|
function requireAccessedPropertyKind(access, checker) {
|
|
4329
|
-
const receiverType = checker.getTypeAtLocation(access.expression);
|
|
4330
|
-
const presentType = access.questionDotToken != null ? checker.getNonNullableType(receiverType) : receiverType;
|
|
4331
|
-
const property = checker.getPropertyOfType(presentType, access.name.text);
|
|
4332
|
-
if (valueKind(presentType, checker) === "object" && property != null && declaredOnlyInDeclarationFiles(property)) {
|
|
4333
|
-
throw unsupported(access, { kind: "prototypeMemberRead", property: access.name.text });
|
|
4334
|
-
}
|
|
4335
4354
|
const type = checker.getTypeAtLocation(access);
|
|
4336
4355
|
if (valueKind(type, checker) != null)
|
|
4337
4356
|
return;
|
|
@@ -4340,17 +4359,12 @@ function requireAccessedPropertyKind(access, checker) {
|
|
|
4340
4359
|
function resolvedSymbol(symbol, checker) {
|
|
4341
4360
|
if (symbol == null)
|
|
4342
4361
|
return null;
|
|
4343
|
-
return (symbol.flags &
|
|
4344
|
-
}
|
|
4345
|
-
function isStandardMathObject(expression, checker) {
|
|
4346
|
-
if (!ts4.isIdentifier(expression) || expression.text !== "Math")
|
|
4347
|
-
return false;
|
|
4348
|
-
return declaredOnlyInDeclarationFiles(checker.getSymbolAtLocation(expression));
|
|
4362
|
+
return (symbol.flags & ts5.SymbolFlags.Alias) === 0 ? symbol : checker.getAliasedSymbol(symbol);
|
|
4349
4363
|
}
|
|
4350
|
-
function
|
|
4351
|
-
if (!
|
|
4364
|
+
function isStandardGlobal(expression, name, context) {
|
|
4365
|
+
if (!ts5.isIdentifier(expression) || expression.text !== name)
|
|
4352
4366
|
return false;
|
|
4353
|
-
return
|
|
4367
|
+
return hasDefaultLibraryDeclaration(context.checker.getSymbolAtLocation(expression), context.program);
|
|
4354
4368
|
}
|
|
4355
4369
|
function lowerElementAccess(access, asserted, context) {
|
|
4356
4370
|
const receiverType = context.checker.getTypeAtLocation(access.expression);
|
|
@@ -4365,7 +4379,7 @@ function lowerElementAccess(access, asserted, context) {
|
|
|
4365
4379
|
requireNumberType(access.argumentExpression, context.checker);
|
|
4366
4380
|
const array = lowerExpression(access.expression, context);
|
|
4367
4381
|
const index = lowerExpression(access.argumentExpression, context);
|
|
4368
|
-
const missingFlag =
|
|
4382
|
+
const missingFlag = ts5.TypeFlags.Undefined;
|
|
4369
4383
|
const staticTypeAllowsUndefined = (resultType.flags & missingFlag) !== 0 || resultType.isUnion() && resultType.types.some((member) => (member.flags & missingFlag) !== 0);
|
|
4370
4384
|
return addInstruction(context, access, {
|
|
4371
4385
|
kind: "arrayIndex",
|
|
@@ -4376,7 +4390,7 @@ function lowerElementAccess(access, asserted, context) {
|
|
|
4376
4390
|
}
|
|
4377
4391
|
function taggedUnionTagRead(expression, context) {
|
|
4378
4392
|
const unwrapped = unwrap(expression, context.checker);
|
|
4379
|
-
if (!
|
|
4393
|
+
if (!ts5.isPropertyAccessExpression(unwrapped))
|
|
4380
4394
|
return null;
|
|
4381
4395
|
const objectType = context.checker.getTypeAtLocation(unwrapped.expression);
|
|
4382
4396
|
if (valueKind(objectType, context.checker) !== "taggedUnion" || !objectType.isUnion())
|
|
@@ -4386,17 +4400,17 @@ function taggedUnionTagRead(expression, context) {
|
|
|
4386
4400
|
}
|
|
4387
4401
|
function tagCheckComparison(expression, context) {
|
|
4388
4402
|
const operator = expression.operatorToken.kind;
|
|
4389
|
-
const equals = operator ===
|
|
4390
|
-
const notEquals = operator ===
|
|
4403
|
+
const equals = operator === ts5.SyntaxKind.EqualsEqualsEqualsToken || operator === ts5.SyntaxKind.EqualsEqualsToken;
|
|
4404
|
+
const notEquals = operator === ts5.SyntaxKind.ExclamationEqualsEqualsToken || operator === ts5.SyntaxKind.ExclamationEqualsToken;
|
|
4391
4405
|
if (!equals && !notEquals)
|
|
4392
4406
|
return null;
|
|
4393
4407
|
const literalOf = (side) => {
|
|
4394
4408
|
const unwrapped = unwrap(side, context.checker);
|
|
4395
|
-
if (
|
|
4409
|
+
if (ts5.isStringLiteral(unwrapped) || ts5.isNoSubstitutionTemplateLiteral(unwrapped))
|
|
4396
4410
|
return unwrapped.text;
|
|
4397
|
-
if (unwrapped.kind ===
|
|
4411
|
+
if (unwrapped.kind === ts5.SyntaxKind.TrueKeyword)
|
|
4398
4412
|
return true;
|
|
4399
|
-
if (unwrapped.kind ===
|
|
4413
|
+
if (unwrapped.kind === ts5.SyntaxKind.FalseKeyword)
|
|
4400
4414
|
return false;
|
|
4401
4415
|
return null;
|
|
4402
4416
|
};
|
|
@@ -4414,7 +4428,7 @@ function tagCheckComparison(expression, context) {
|
|
|
4414
4428
|
}
|
|
4415
4429
|
function opaqueEqualityCheck(expression, context) {
|
|
4416
4430
|
const operator = expression.operatorToken.kind;
|
|
4417
|
-
const isEquality = operator ===
|
|
4431
|
+
const isEquality = operator === ts5.SyntaxKind.EqualsEqualsEqualsToken || operator === ts5.SyntaxKind.ExclamationEqualsEqualsToken || operator === ts5.SyntaxKind.EqualsEqualsToken || operator === ts5.SyntaxKind.ExclamationEqualsToken;
|
|
4418
4432
|
if (!isEquality)
|
|
4419
4433
|
return null;
|
|
4420
4434
|
const opaqueOrMissingOpaque = (side) => {
|
|
@@ -4423,7 +4437,7 @@ function opaqueEqualityCheck(expression, context) {
|
|
|
4423
4437
|
if (kind === "opaque")
|
|
4424
4438
|
return true;
|
|
4425
4439
|
if (kind === "nullable" && type.isUnion()) {
|
|
4426
|
-
const missing =
|
|
4440
|
+
const missing = ts5.TypeFlags.Null | ts5.TypeFlags.Undefined;
|
|
4427
4441
|
const rest = type.types.filter((member) => (member.flags & missing) === 0);
|
|
4428
4442
|
return rest.length >= 1 && rest.every((member) => valueKind(member, context.checker) === "opaque");
|
|
4429
4443
|
}
|
|
@@ -4437,14 +4451,14 @@ function opaqueEqualityCheck(expression, context) {
|
|
|
4437
4451
|
}
|
|
4438
4452
|
function missingSentinelCheck(expression, context) {
|
|
4439
4453
|
const operator = expression.operatorToken.kind;
|
|
4440
|
-
const strict = operator ===
|
|
4441
|
-
const loose = operator ===
|
|
4454
|
+
const strict = operator === ts5.SyntaxKind.EqualsEqualsEqualsToken || operator === ts5.SyntaxKind.ExclamationEqualsEqualsToken;
|
|
4455
|
+
const loose = operator === ts5.SyntaxKind.EqualsEqualsToken || operator === ts5.SyntaxKind.ExclamationEqualsToken;
|
|
4442
4456
|
if (!strict && !loose)
|
|
4443
4457
|
return null;
|
|
4444
|
-
const negated = operator ===
|
|
4458
|
+
const negated = operator === ts5.SyntaxKind.ExclamationEqualsEqualsToken || operator === ts5.SyntaxKind.ExclamationEqualsToken;
|
|
4445
4459
|
const sentinelOf = (side) => {
|
|
4446
4460
|
const unwrapped = unwrap(side, context.checker);
|
|
4447
|
-
if (unwrapped.kind ===
|
|
4461
|
+
if (unwrapped.kind === ts5.SyntaxKind.NullKeyword)
|
|
4448
4462
|
return "null";
|
|
4449
4463
|
if (isUndefinedGlobal(unwrapped, context.checker))
|
|
4450
4464
|
return "undefined";
|
|
@@ -4452,39 +4466,39 @@ function missingSentinelCheck(expression, context) {
|
|
|
4452
4466
|
};
|
|
4453
4467
|
const isUndefinedString = (side) => {
|
|
4454
4468
|
const unwrapped = unwrap(side, context.checker);
|
|
4455
|
-
return
|
|
4469
|
+
return ts5.isStringLiteral(unwrapped) && unwrapped.text === "undefined";
|
|
4456
4470
|
};
|
|
4457
|
-
if (
|
|
4471
|
+
if (ts5.isTypeOfExpression(expression.left) && isUndefinedString(expression.right)) {
|
|
4458
4472
|
const value3 = lowerExpression(expression.left.expression, context);
|
|
4459
4473
|
return addInstruction(context, expression, { kind: "nullishCheck", value: value3, sentinel: "undefined", negated });
|
|
4460
4474
|
}
|
|
4461
|
-
if (
|
|
4475
|
+
if (ts5.isTypeOfExpression(expression.right) && isUndefinedString(expression.left)) {
|
|
4462
4476
|
const value3 = lowerExpression(expression.right.expression, context);
|
|
4463
4477
|
return addInstruction(context, expression, { kind: "nullishCheck", value: value3, sentinel: "undefined", negated });
|
|
4464
4478
|
}
|
|
4465
4479
|
const primitiveTypeofFlags = (side) => {
|
|
4466
4480
|
const unwrapped = unwrap(side, context.checker);
|
|
4467
|
-
if (!
|
|
4481
|
+
if (!ts5.isStringLiteral(unwrapped))
|
|
4468
4482
|
return null;
|
|
4469
4483
|
switch (unwrapped.text) {
|
|
4470
4484
|
case "number":
|
|
4471
|
-
return
|
|
4485
|
+
return ts5.TypeFlags.NumberLike;
|
|
4472
4486
|
case "string":
|
|
4473
|
-
return
|
|
4487
|
+
return ts5.TypeFlags.StringLike;
|
|
4474
4488
|
case "boolean":
|
|
4475
|
-
return
|
|
4489
|
+
return ts5.TypeFlags.BooleanLike;
|
|
4476
4490
|
default:
|
|
4477
4491
|
return null;
|
|
4478
4492
|
}
|
|
4479
4493
|
};
|
|
4480
4494
|
const rightFlags = primitiveTypeofFlags(expression.right);
|
|
4481
4495
|
const leftFlags = primitiveTypeofFlags(expression.left);
|
|
4482
|
-
const typeofSide =
|
|
4496
|
+
const typeofSide = ts5.isTypeOfExpression(expression.left) && rightFlags != null ? { operand: expression.left, flags: rightFlags } : ts5.isTypeOfExpression(expression.right) && leftFlags != null ? { operand: expression.right, flags: leftFlags } : null;
|
|
4483
4497
|
if (typeofSide != null) {
|
|
4484
4498
|
const operandType = context.checker.getTypeAtLocation(typeofSide.operand.expression);
|
|
4485
|
-
const missing =
|
|
4499
|
+
const missing = ts5.TypeFlags.Null | ts5.TypeFlags.Undefined;
|
|
4486
4500
|
const members = operandType.isUnion() ? operandType.types : [operandType];
|
|
4487
|
-
const restMatches = members.every((member) => (member.flags & missing) !== 0 || (member.flags & typeofSide.flags) !== 0) && members.some((member) => (member.flags & missing) === 0);
|
|
4501
|
+
const restMatches = members.every((member) => (member.flags & missing) !== 0 || (typeofSide.flags === ts5.TypeFlags.NumberLike ? valueKind(member, context.checker) === "number" : (member.flags & typeofSide.flags) !== 0)) && members.some((member) => (member.flags & missing) === 0);
|
|
4488
4502
|
const value3 = lowerExpression(typeofSide.operand.expression, context);
|
|
4489
4503
|
if (restMatches) {
|
|
4490
4504
|
return addInstruction(context, expression, { kind: "nullishCheck", value: value3, sentinel: "nullish", negated: !negated });
|
|
@@ -4498,7 +4512,7 @@ function missingSentinelCheck(expression, context) {
|
|
|
4498
4512
|
return null;
|
|
4499
4513
|
const checked = leftSentinel == null ? expression.left : expression.right;
|
|
4500
4514
|
const checkedType = context.checker.getTypeAtLocation(checked);
|
|
4501
|
-
const missingFlags =
|
|
4515
|
+
const missingFlags = ts5.TypeFlags.Null | ts5.TypeFlags.Undefined;
|
|
4502
4516
|
const pureSentinel = (checkedType.flags & missingFlags) !== 0 || checkedType.isUnion() && checkedType.types.every((member) => (member.flags & missingFlags) !== 0);
|
|
4503
4517
|
if (!pureSentinel && valueKind(checkedType, context.checker) == null) {
|
|
4504
4518
|
throw unsupported(checked, { kind: "valueType", typeText: context.checker.typeToString(checkedType) });
|
|
@@ -4511,11 +4525,6 @@ function missingSentinelCheck(expression, context) {
|
|
|
4511
4525
|
negated
|
|
4512
4526
|
});
|
|
4513
4527
|
}
|
|
4514
|
-
function isGlobalInfinity(expression, checker) {
|
|
4515
|
-
if (!ts4.isIdentifier(expression) || expression.text !== "Infinity")
|
|
4516
|
-
return false;
|
|
4517
|
-
return declaredOnlyInDeclarationFiles(checker.getSymbolAtLocation(expression));
|
|
4518
|
-
}
|
|
4519
4528
|
function identifierValue(symbol, node, context) {
|
|
4520
4529
|
const local = context.bindings.get(symbol);
|
|
4521
4530
|
if (local != null)
|
|
@@ -4523,7 +4532,7 @@ function identifierValue(symbol, node, context) {
|
|
|
4523
4532
|
const binding = context.moduleBindingsBySymbol.get(symbol);
|
|
4524
4533
|
if (binding != null)
|
|
4525
4534
|
return addInstruction(context, node, { kind: "moduleRead", binding });
|
|
4526
|
-
if (
|
|
4535
|
+
if (isStandardGlobal(node, "Infinity", context)) {
|
|
4527
4536
|
return addInstruction(context, node, { kind: "constant", value: Number.POSITIVE_INFINITY });
|
|
4528
4537
|
}
|
|
4529
4538
|
if (isUndefinedGlobal(node, context.checker)) {
|
|
@@ -4542,25 +4551,25 @@ function assignIdentifier(symbol, node, value2, wholeExpression, context) {
|
|
|
4542
4551
|
throw unsupported(node, { kind: "unknownIdentifier", name: node.text });
|
|
4543
4552
|
}
|
|
4544
4553
|
function propertyName(name) {
|
|
4545
|
-
if (
|
|
4554
|
+
if (ts5.isIdentifier(name) || ts5.isStringLiteral(name) || ts5.isNumericLiteral(name))
|
|
4546
4555
|
return name.text;
|
|
4547
4556
|
throw unsupported(name, { kind: "computedPropertyName" });
|
|
4548
4557
|
}
|
|
4549
4558
|
function unwrap(expression, checker) {
|
|
4550
4559
|
let current = expression;
|
|
4551
4560
|
while (true) {
|
|
4552
|
-
if (
|
|
4561
|
+
if (ts5.isParenthesizedExpression(current) || ts5.isSatisfiesExpression(current)) {
|
|
4553
4562
|
current = current.expression;
|
|
4554
4563
|
continue;
|
|
4555
4564
|
}
|
|
4556
|
-
if ((
|
|
4565
|
+
if ((ts5.isAsExpression(current) || ts5.isTypeAssertionExpression(current)) && ts5.isConstTypeReference(current.type)) {
|
|
4557
4566
|
current = current.expression;
|
|
4558
4567
|
continue;
|
|
4559
4568
|
}
|
|
4560
|
-
if (
|
|
4569
|
+
if (ts5.isNonNullExpression(current)) {
|
|
4561
4570
|
const assertedType = checker.getTypeAtLocation(current);
|
|
4562
4571
|
const operandType = checker.getTypeAtLocation(current.expression);
|
|
4563
|
-
if (
|
|
4572
|
+
if (ts5.isElementAccessExpression(current.expression) && valueKind(assertedType, checker) != null) {
|
|
4564
4573
|
return current;
|
|
4565
4574
|
}
|
|
4566
4575
|
if (valueKind(assertedType, checker) !== valueKind(operandType, checker)) {
|
|
@@ -4578,17 +4587,17 @@ function unwrap(expression, checker) {
|
|
|
4578
4587
|
}
|
|
4579
4588
|
|
|
4580
4589
|
// src/lower/function-unit.ts
|
|
4581
|
-
import * as
|
|
4590
|
+
import * as ts6 from "typescript";
|
|
4582
4591
|
function callableSignature(unit, checker) {
|
|
4583
4592
|
if (unit.initializer == null) {
|
|
4584
4593
|
return checker.getSignatureFromDeclaration(unit.declaration) ?? null;
|
|
4585
4594
|
}
|
|
4586
|
-
const signatures = checker.getSignaturesOfType(checker.getTypeAtLocation(unit.name),
|
|
4595
|
+
const signatures = checker.getSignaturesOfType(checker.getTypeAtLocation(unit.name), ts6.SignatureKind.Call);
|
|
4587
4596
|
if (signatures.length !== 1)
|
|
4588
4597
|
return null;
|
|
4589
4598
|
const signature = signatures[0];
|
|
4590
4599
|
const signatureDeclaration = signature.declaration;
|
|
4591
|
-
if (signatureDeclaration == null || signature.thisParameter != null || signature.parameters.length !== unit.declaration.parameters.length || signatureDeclaration.parameters.some((parameter) => !
|
|
4600
|
+
if (signatureDeclaration == null || signature.thisParameter != null || signature.parameters.length !== unit.declaration.parameters.length || signatureDeclaration.parameters.some((parameter) => !ts6.isParameter(parameter) || parameter.dotDotDotToken != null)) {
|
|
4592
4601
|
return null;
|
|
4593
4602
|
}
|
|
4594
4603
|
return signature;
|
|
@@ -4596,14 +4605,14 @@ function callableSignature(unit, checker) {
|
|
|
4596
4605
|
function topLevelFunctionUnits(sourceFile) {
|
|
4597
4606
|
const units = [];
|
|
4598
4607
|
for (const statement of sourceFile.statements) {
|
|
4599
|
-
if (
|
|
4608
|
+
if (ts6.isFunctionDeclaration(statement) && statement.name != null) {
|
|
4600
4609
|
units.push({ name: statement.name, declaration: statement, initializer: null });
|
|
4601
4610
|
continue;
|
|
4602
4611
|
}
|
|
4603
|
-
if (!
|
|
4612
|
+
if (!ts6.isVariableStatement(statement) || (statement.declarationList.flags & ts6.NodeFlags.Const) === 0)
|
|
4604
4613
|
continue;
|
|
4605
4614
|
for (const initializer of statement.declarationList.declarations) {
|
|
4606
|
-
if (!
|
|
4615
|
+
if (!ts6.isIdentifier(initializer.name) || initializer.initializer == null)
|
|
4607
4616
|
continue;
|
|
4608
4617
|
const declaration = directFunctionExpression(initializer.initializer);
|
|
4609
4618
|
if (declaration != null) {
|
|
@@ -4614,14 +4623,14 @@ function topLevelFunctionUnits(sourceFile) {
|
|
|
4614
4623
|
return units;
|
|
4615
4624
|
}
|
|
4616
4625
|
function directFunctionExpression(expression) {
|
|
4617
|
-
return
|
|
4626
|
+
return ts6.isArrowFunction(expression) || ts6.isFunctionExpression(expression) ? expression : null;
|
|
4618
4627
|
}
|
|
4619
4628
|
|
|
4620
4629
|
// src/lower/module.ts
|
|
4621
|
-
import * as
|
|
4630
|
+
import * as ts8 from "typescript";
|
|
4622
4631
|
|
|
4623
4632
|
// src/lower/statements.ts
|
|
4624
|
-
import * as
|
|
4633
|
+
import * as ts7 from "typescript";
|
|
4625
4634
|
function lowerStatements(statements, context) {
|
|
4626
4635
|
for (const statement of statements) {
|
|
4627
4636
|
if (context.currentBlock.terminator != null)
|
|
@@ -4630,11 +4639,11 @@ function lowerStatements(statements, context) {
|
|
|
4630
4639
|
}
|
|
4631
4640
|
}
|
|
4632
4641
|
function lowerStatement(statement, context) {
|
|
4633
|
-
if (
|
|
4642
|
+
if (ts7.isVariableStatement(statement)) {
|
|
4634
4643
|
lowerVariableDeclarationList(statement.declarationList, context);
|
|
4635
4644
|
return;
|
|
4636
4645
|
}
|
|
4637
|
-
if (
|
|
4646
|
+
if (ts7.isReturnStatement(statement)) {
|
|
4638
4647
|
let value2 = statement.expression == null ? null : lowerExpression(statement.expression, context);
|
|
4639
4648
|
if (context.returnsVoid)
|
|
4640
4649
|
value2 = null;
|
|
@@ -4644,43 +4653,43 @@ function lowerStatement(statement, context) {
|
|
|
4644
4653
|
terminate(context.currentBlock, { kind: "return", value: value2, site: addSite(context, statement) });
|
|
4645
4654
|
return;
|
|
4646
4655
|
}
|
|
4647
|
-
if (
|
|
4656
|
+
if (ts7.isExpressionStatement(statement)) {
|
|
4648
4657
|
lowerStatementExpression(statement.expression, context);
|
|
4649
4658
|
return;
|
|
4650
4659
|
}
|
|
4651
|
-
if (
|
|
4660
|
+
if (ts7.isIfStatement(statement)) {
|
|
4652
4661
|
lowerIfStatement(statement, context);
|
|
4653
4662
|
return;
|
|
4654
4663
|
}
|
|
4655
|
-
if (
|
|
4664
|
+
if (ts7.isForOfStatement(statement)) {
|
|
4656
4665
|
lowerForOfStatement(statement, context);
|
|
4657
4666
|
return;
|
|
4658
4667
|
}
|
|
4659
|
-
if (
|
|
4668
|
+
if (ts7.isForStatement(statement)) {
|
|
4660
4669
|
lowerForStatement(statement, context);
|
|
4661
4670
|
return;
|
|
4662
4671
|
}
|
|
4663
|
-
if (
|
|
4672
|
+
if (ts7.isWhileStatement(statement)) {
|
|
4664
4673
|
lowerWhileStatement(statement, context);
|
|
4665
4674
|
return;
|
|
4666
4675
|
}
|
|
4667
|
-
if (
|
|
4676
|
+
if (ts7.isContinueStatement(statement)) {
|
|
4668
4677
|
lowerContinueStatement(statement, context);
|
|
4669
4678
|
return;
|
|
4670
4679
|
}
|
|
4671
|
-
if (
|
|
4680
|
+
if (ts7.isBlock(statement)) {
|
|
4672
4681
|
lowerStatements(statement.statements, context);
|
|
4673
4682
|
return;
|
|
4674
4683
|
}
|
|
4675
|
-
if (
|
|
4684
|
+
if (ts7.isSwitchStatement(statement)) {
|
|
4676
4685
|
lowerSwitchStatement(statement, context);
|
|
4677
4686
|
return;
|
|
4678
4687
|
}
|
|
4679
|
-
if (
|
|
4688
|
+
if (ts7.isThrowStatement(statement)) {
|
|
4680
4689
|
terminate(context.currentBlock, { kind: "thrown", site: addSite(context, statement) });
|
|
4681
4690
|
return;
|
|
4682
4691
|
}
|
|
4683
|
-
throw unsupported(statement, { kind: "statementForm", syntax:
|
|
4692
|
+
throw unsupported(statement, { kind: "statementForm", syntax: ts7.SyntaxKind[statement.kind] });
|
|
4684
4693
|
}
|
|
4685
4694
|
function lowerIfStatement(statement, context) {
|
|
4686
4695
|
const bindingsBeforeBranch = new Map(context.bindings);
|
|
@@ -4707,7 +4716,7 @@ function lowerSwitchStatement(statement, context) {
|
|
|
4707
4716
|
const subjectType = context.checker.getTypeAtLocation(statement.expression);
|
|
4708
4717
|
const subjectKind = valueKind(subjectType, context.checker);
|
|
4709
4718
|
const tagUnionExpression = taggedUnionTagRead(statement.expression, context);
|
|
4710
|
-
const missingFlags =
|
|
4719
|
+
const missingFlags = ts7.TypeFlags.Null | ts7.TypeFlags.Undefined;
|
|
4711
4720
|
const nullableOpaqueSubject = subjectKind === "nullable" && subjectType.isUnion() && subjectType.types.every((member) => (member.flags & missingFlags) !== 0 || valueKind(member, context.checker) === "opaque");
|
|
4712
4721
|
if (tagUnionExpression == null && subjectKind !== "number" && subjectKind !== "opaque" && !nullableOpaqueSubject) {
|
|
4713
4722
|
throw unsupported(statement.expression, { kind: "switchSubject", typeText: context.checker.typeToString(subjectType) });
|
|
@@ -4719,7 +4728,7 @@ function lowerSwitchStatement(statement, context) {
|
|
|
4719
4728
|
const clauses = statement.caseBlock.clauses;
|
|
4720
4729
|
for (let index = 0;index < clauses.length; index++) {
|
|
4721
4730
|
const clause = clauses[index];
|
|
4722
|
-
if (
|
|
4731
|
+
if (ts7.isDefaultClause(clause)) {
|
|
4723
4732
|
if (index !== clauses.length - 1 || pendingLabels.length > 0) {
|
|
4724
4733
|
throw unsupported(clause, { kind: "switchDefaultNotLast" });
|
|
4725
4734
|
}
|
|
@@ -4740,7 +4749,7 @@ function lowerSwitchStatement(statement, context) {
|
|
|
4740
4749
|
const lowerBody = (group) => {
|
|
4741
4750
|
const body = group.statements;
|
|
4742
4751
|
const last = body[body.length - 1];
|
|
4743
|
-
const endsWithBreak = last != null &&
|
|
4752
|
+
const endsWithBreak = last != null && ts7.isBreakStatement(last);
|
|
4744
4753
|
lowerStatements(endsWithBreak ? body.slice(0, -1) : body, context);
|
|
4745
4754
|
if (context.currentBlock.terminator == null) {
|
|
4746
4755
|
if (!endsWithBreak)
|
|
@@ -4759,7 +4768,7 @@ function lowerSwitchStatement(statement, context) {
|
|
|
4759
4768
|
let condition;
|
|
4760
4769
|
if (tagUnionExpression != null) {
|
|
4761
4770
|
const unwrappedLabel = label;
|
|
4762
|
-
if (!
|
|
4771
|
+
if (!ts7.isStringLiteral(unwrappedLabel) && !ts7.isNoSubstitutionTemplateLiteral(unwrappedLabel)) {
|
|
4763
4772
|
throw unsupported(label, { kind: "switchLabel", typeText: context.checker.typeToString(context.checker.getTypeAtLocation(label)) });
|
|
4764
4773
|
}
|
|
4765
4774
|
condition = addInstruction(context, label, { kind: "tagCheck", union: subject, tagValue: unwrappedLabel.text, negated: false });
|
|
@@ -4801,7 +4810,7 @@ function lowerSwitchStatement(statement, context) {
|
|
|
4801
4810
|
mergeAtContinuation(exits, bindingsBefore, statement, context);
|
|
4802
4811
|
}
|
|
4803
4812
|
function lowerForOfStatement(statement, context) {
|
|
4804
|
-
if (!
|
|
4813
|
+
if (!ts7.isVariableDeclarationList(statement.initializer) || statement.initializer.declarations.length !== 1 || !ts7.isIdentifier(statement.initializer.declarations[0].name)) {
|
|
4805
4814
|
throw unsupported(statement.initializer, { kind: "variableDeclarationShape" });
|
|
4806
4815
|
}
|
|
4807
4816
|
const elementName = statement.initializer.declarations[0].name;
|
|
@@ -4878,7 +4887,7 @@ function lowerForOfStatement(statement, context) {
|
|
|
4878
4887
|
}
|
|
4879
4888
|
function lowerForStatement(statement, context) {
|
|
4880
4889
|
if (statement.initializer != null) {
|
|
4881
|
-
if (
|
|
4890
|
+
if (ts7.isVariableDeclarationList(statement.initializer)) {
|
|
4882
4891
|
lowerVariableDeclarationList(statement.initializer, context);
|
|
4883
4892
|
} else {
|
|
4884
4893
|
lowerStatementExpression(statement.initializer, context);
|
|
@@ -4987,21 +4996,16 @@ function lowerBranch(statement, block, bindings, context) {
|
|
|
4987
4996
|
}
|
|
4988
4997
|
function lowerVariableDeclarationList(declarations, context) {
|
|
4989
4998
|
for (const declaration of declarations.declarations) {
|
|
4990
|
-
if (
|
|
4999
|
+
if (ts7.isObjectBindingPattern(declaration.name) && declaration.initializer != null) {
|
|
4991
5000
|
const source = lowerExpression(declaration.initializer, context);
|
|
4992
5001
|
for (const element of declaration.name.elements) {
|
|
4993
|
-
if (!
|
|
5002
|
+
if (!ts7.isIdentifier(element.name) || element.dotDotDotToken != null || element.initializer != null) {
|
|
4994
5003
|
throw unsupported(element, { kind: "variableDeclarationShape" });
|
|
4995
5004
|
}
|
|
4996
|
-
const property = element.propertyName == null ? element.name.text :
|
|
5005
|
+
const property = element.propertyName == null ? element.name.text : ts7.isIdentifier(element.propertyName) ? element.propertyName.text : null;
|
|
4997
5006
|
if (property == null)
|
|
4998
5007
|
throw unsupported(element, { kind: "variableDeclarationShape" });
|
|
4999
5008
|
const elementType = context.checker.getTypeAtLocation(element.name);
|
|
5000
|
-
const sourceType = context.checker.getTypeAtLocation(declaration.initializer);
|
|
5001
|
-
const propertySymbol = context.checker.getPropertyOfType(sourceType, property);
|
|
5002
|
-
if (propertySymbol != null && declaredOnlyInDeclarationFiles(propertySymbol)) {
|
|
5003
|
-
throw unsupported(element, { kind: "prototypeMemberRead", property });
|
|
5004
|
-
}
|
|
5005
5009
|
if (valueKind(elementType, context.checker) == null) {
|
|
5006
5010
|
throw unsupported(element, { kind: "valueType", typeText: context.checker.typeToString(elementType) });
|
|
5007
5011
|
}
|
|
@@ -5010,7 +5014,7 @@ function lowerVariableDeclarationList(declarations, context) {
|
|
|
5010
5014
|
}
|
|
5011
5015
|
continue;
|
|
5012
5016
|
}
|
|
5013
|
-
if (!
|
|
5017
|
+
if (!ts7.isIdentifier(declaration.name) || declaration.initializer == null) {
|
|
5014
5018
|
throw unsupported(declaration, { kind: "variableDeclarationShape" });
|
|
5015
5019
|
}
|
|
5016
5020
|
const value2 = lowerExpression(declaration.initializer, context);
|
|
@@ -5029,12 +5033,12 @@ function lowerVariableDeclarationList(declarations, context) {
|
|
|
5029
5033
|
function assignedSymbols(nodes, checker) {
|
|
5030
5034
|
const symbols = new Set;
|
|
5031
5035
|
const visit = (node) => {
|
|
5032
|
-
if (
|
|
5036
|
+
if (ts7.isFunctionLike(node))
|
|
5033
5037
|
return;
|
|
5034
5038
|
const assignment = identifierAssignment(node);
|
|
5035
5039
|
if (assignment != null)
|
|
5036
5040
|
symbols.add(requiredSymbol(assignment.target, checker));
|
|
5037
|
-
|
|
5041
|
+
ts7.forEachChild(node, visit);
|
|
5038
5042
|
};
|
|
5039
5043
|
for (const node of nodes)
|
|
5040
5044
|
visit(node);
|
|
@@ -5053,46 +5057,46 @@ function scanModuleBindings(sourceFile, checker) {
|
|
|
5053
5057
|
bindings.push({ name: name.text, category });
|
|
5054
5058
|
};
|
|
5055
5059
|
for (const statement of sourceFile.statements) {
|
|
5056
|
-
if (
|
|
5057
|
-
if ((statement.declarationList.flags & (
|
|
5060
|
+
if (ts8.isVariableStatement(statement)) {
|
|
5061
|
+
if ((statement.declarationList.flags & (ts8.NodeFlags.Let | ts8.NodeFlags.Const)) === 0)
|
|
5058
5062
|
continue;
|
|
5059
|
-
const isConst = (statement.declarationList.flags &
|
|
5063
|
+
const isConst = (statement.declarationList.flags & ts8.NodeFlags.Const) !== 0;
|
|
5060
5064
|
for (const declarator of statement.declarationList.declarations) {
|
|
5061
|
-
if (
|
|
5065
|
+
if (ts8.isIdentifier(declarator.name)) {
|
|
5062
5066
|
register(declarator.name, isConst && declarator.initializer != null && directFunctionExpression(declarator.initializer) != null ? { kind: "function" } : declaredCategory(declarator.name, checker));
|
|
5063
5067
|
continue;
|
|
5064
5068
|
}
|
|
5065
|
-
if (
|
|
5069
|
+
if (ts8.isObjectBindingPattern(declarator.name)) {
|
|
5066
5070
|
for (const element of declarator.name.elements) {
|
|
5067
|
-
if (
|
|
5071
|
+
if (ts8.isIdentifier(element.name))
|
|
5068
5072
|
register(element.name, declaredCategory(element.name, checker));
|
|
5069
5073
|
}
|
|
5070
5074
|
}
|
|
5071
5075
|
}
|
|
5072
5076
|
continue;
|
|
5073
5077
|
}
|
|
5074
|
-
if (
|
|
5078
|
+
if (ts8.isImportDeclaration(statement)) {
|
|
5075
5079
|
const clause = statement.importClause;
|
|
5076
5080
|
if (clause == null || clause.isTypeOnly)
|
|
5077
5081
|
continue;
|
|
5078
5082
|
if (clause.name != null)
|
|
5079
5083
|
register(clause.name, importedCategory(clause.name, checker));
|
|
5080
5084
|
const named = clause.namedBindings;
|
|
5081
|
-
if (named != null &&
|
|
5085
|
+
if (named != null && ts8.isNamedImports(named)) {
|
|
5082
5086
|
for (const element of named.elements) {
|
|
5083
5087
|
if (!element.isTypeOnly)
|
|
5084
5088
|
register(element.name, importedCategory(element.name, checker));
|
|
5085
5089
|
}
|
|
5086
5090
|
}
|
|
5087
|
-
if (named != null &&
|
|
5091
|
+
if (named != null && ts8.isNamespaceImport(named))
|
|
5088
5092
|
register(named.name, { kind: "import" });
|
|
5089
5093
|
}
|
|
5090
5094
|
}
|
|
5091
5095
|
const visit = (node, insideFunction) => {
|
|
5092
5096
|
if (insideFunction)
|
|
5093
5097
|
demoteModuleWritesInNode(node, checker, bindingsBySymbol, bindings);
|
|
5094
|
-
const enteringFunction = insideFunction ||
|
|
5095
|
-
|
|
5098
|
+
const enteringFunction = insideFunction || ts8.isFunctionLike(node);
|
|
5099
|
+
ts8.forEachChild(node, (child) => {
|
|
5096
5100
|
visit(child, enteringFunction);
|
|
5097
5101
|
});
|
|
5098
5102
|
};
|
|
@@ -5101,13 +5105,13 @@ function scanModuleBindings(sourceFile, checker) {
|
|
|
5101
5105
|
}
|
|
5102
5106
|
function importedCategory(name, checker) {
|
|
5103
5107
|
const symbol = checker.getSymbolAtLocation(name);
|
|
5104
|
-
if (symbol == null || (symbol.flags &
|
|
5108
|
+
if (symbol == null || (symbol.flags & ts8.SymbolFlags.Alias) === 0)
|
|
5105
5109
|
return { kind: "import" };
|
|
5106
5110
|
const target = checker.getAliasedSymbol(symbol);
|
|
5107
5111
|
const declaration = target.valueDeclaration;
|
|
5108
|
-
if (declaration == null || !
|
|
5112
|
+
if (declaration == null || !ts8.isVariableDeclaration(declaration))
|
|
5109
5113
|
return { kind: "import" };
|
|
5110
|
-
if ((
|
|
5114
|
+
if ((ts8.getCombinedNodeFlags(declaration) & ts8.NodeFlags.Const) === 0)
|
|
5111
5115
|
return { kind: "import" };
|
|
5112
5116
|
if (declaration.getSourceFile().isDeclarationFile)
|
|
5113
5117
|
return { kind: "import" };
|
|
@@ -5123,7 +5127,7 @@ function demoteModuleWritesInNode(node, checker, bindingsBySymbol, bindings, wri
|
|
|
5123
5127
|
written[binding] = true;
|
|
5124
5128
|
};
|
|
5125
5129
|
const target = (expression) => {
|
|
5126
|
-
if (
|
|
5130
|
+
if (ts8.isIdentifier(expression)) {
|
|
5127
5131
|
const symbol = checker.getSymbolAtLocation(expression);
|
|
5128
5132
|
const binding = symbol == null ? undefined : bindingsBySymbol.get(symbol);
|
|
5129
5133
|
if (binding != null)
|
|
@@ -5131,39 +5135,39 @@ function demoteModuleWritesInNode(node, checker, bindingsBySymbol, bindings, wri
|
|
|
5131
5135
|
return;
|
|
5132
5136
|
}
|
|
5133
5137
|
const visitPattern = (child) => {
|
|
5134
|
-
if (
|
|
5138
|
+
if (ts8.isShorthandPropertyAssignment(child)) {
|
|
5135
5139
|
const symbol = checker.getShorthandAssignmentValueSymbol(child);
|
|
5136
5140
|
const binding = symbol == null ? undefined : bindingsBySymbol.get(symbol);
|
|
5137
5141
|
if (binding != null)
|
|
5138
5142
|
record(binding);
|
|
5139
|
-
|
|
5143
|
+
ts8.forEachChild(child, visitPattern);
|
|
5140
5144
|
return;
|
|
5141
5145
|
}
|
|
5142
|
-
if (
|
|
5146
|
+
if (ts8.isIdentifier(child)) {
|
|
5143
5147
|
const symbol = checker.getSymbolAtLocation(child);
|
|
5144
5148
|
const binding = symbol == null ? undefined : bindingsBySymbol.get(symbol);
|
|
5145
5149
|
if (binding != null)
|
|
5146
5150
|
record(binding);
|
|
5147
5151
|
return;
|
|
5148
5152
|
}
|
|
5149
|
-
|
|
5153
|
+
ts8.forEachChild(child, visitPattern);
|
|
5150
5154
|
};
|
|
5151
|
-
|
|
5155
|
+
ts8.forEachChild(expression, visitPattern);
|
|
5152
5156
|
};
|
|
5153
|
-
if (
|
|
5157
|
+
if (ts8.isBinaryExpression(node)) {
|
|
5154
5158
|
const kind = node.operatorToken.kind;
|
|
5155
|
-
if (kind >=
|
|
5159
|
+
if (kind >= ts8.SyntaxKind.FirstAssignment && kind <= ts8.SyntaxKind.LastAssignment)
|
|
5156
5160
|
target(node.left);
|
|
5157
5161
|
}
|
|
5158
|
-
if ((
|
|
5162
|
+
if ((ts8.isPrefixUnaryExpression(node) || ts8.isPostfixUnaryExpression(node)) && (node.operator === ts8.SyntaxKind.PlusPlusToken || node.operator === ts8.SyntaxKind.MinusMinusToken) && ts8.isExpression(node.operand)) {
|
|
5159
5163
|
target(node.operand);
|
|
5160
5164
|
}
|
|
5161
|
-
if ((
|
|
5165
|
+
if ((ts8.isForOfStatement(node) || ts8.isForInStatement(node)) && ts8.isExpression(node.initializer)) {
|
|
5162
5166
|
target(node.initializer);
|
|
5163
5167
|
}
|
|
5164
5168
|
}
|
|
5165
|
-
function lowerModuleInitializer(sourceFile, checker, functionsBySymbol, scan, sites) {
|
|
5166
|
-
const context = createFunctionContext(sourceFile, checker, functionsBySymbol, scan.bindingsBySymbol, sites);
|
|
5169
|
+
function lowerModuleInitializer(sourceFile, checker, program, functionsBySymbol, scan, sites) {
|
|
5170
|
+
const context = createFunctionContext(sourceFile, checker, program, functionsBySymbol, scan.bindingsBySymbol, sites);
|
|
5167
5171
|
const skips = [];
|
|
5168
5172
|
const statements = sourceFile.statements;
|
|
5169
5173
|
for (const statement of statements) {
|
|
@@ -5172,7 +5176,7 @@ function lowerModuleInitializer(sourceFile, checker, functionsBySymbol, scan, si
|
|
|
5172
5176
|
const recovery = snapshotLowering(context);
|
|
5173
5177
|
try {
|
|
5174
5178
|
assertAccepted(statement, true);
|
|
5175
|
-
if (
|
|
5179
|
+
if (ts8.isVariableStatement(statement)) {
|
|
5176
5180
|
lowerTopLevelDeclarations(statement, context, scan);
|
|
5177
5181
|
continue;
|
|
5178
5182
|
}
|
|
@@ -5210,31 +5214,31 @@ function lowerModuleInitializer(sourceFile, checker, functionsBySymbol, scan, si
|
|
|
5210
5214
|
};
|
|
5211
5215
|
}
|
|
5212
5216
|
function containsArrayLiteral(root) {
|
|
5213
|
-
if (
|
|
5217
|
+
if (ts8.isArrayLiteralExpression(root))
|
|
5214
5218
|
return true;
|
|
5215
5219
|
let found = false;
|
|
5216
|
-
|
|
5220
|
+
ts8.forEachChild(root, (child) => {
|
|
5217
5221
|
if (!found && containsArrayLiteral(child))
|
|
5218
5222
|
found = true;
|
|
5219
5223
|
});
|
|
5220
5224
|
return found;
|
|
5221
5225
|
}
|
|
5222
5226
|
function forEachImmediatelyEvaluatedChild(node, visit) {
|
|
5223
|
-
if (
|
|
5224
|
-
if (node.name != null &&
|
|
5227
|
+
if (ts8.isFunctionLike(node)) {
|
|
5228
|
+
if (node.name != null && ts8.isComputedPropertyName(node.name)) {
|
|
5225
5229
|
visit(node.name.expression);
|
|
5226
5230
|
}
|
|
5227
5231
|
return;
|
|
5228
5232
|
}
|
|
5229
|
-
|
|
5233
|
+
ts8.forEachChild(node, visit);
|
|
5230
5234
|
}
|
|
5231
5235
|
function lowerSupportedArgumentsOfSkippedTopLevelCall(statement, stop, context) {
|
|
5232
|
-
if (!
|
|
5236
|
+
if (!ts8.isExpressionStatement(statement))
|
|
5233
5237
|
return;
|
|
5234
5238
|
let expression = statement.expression;
|
|
5235
|
-
while (
|
|
5239
|
+
while (ts8.isParenthesizedExpression(expression))
|
|
5236
5240
|
expression = expression.expression;
|
|
5237
|
-
if (!
|
|
5241
|
+
if (!ts8.isCallExpression(expression) || expression !== stop.node || expression.questionDotToken != null || !plainCallTarget(expression.expression))
|
|
5238
5242
|
return;
|
|
5239
5243
|
for (const argument of expression.arguments) {
|
|
5240
5244
|
const recovery = snapshotLowering(context);
|
|
@@ -5249,23 +5253,23 @@ function lowerSupportedArgumentsOfSkippedTopLevelCall(statement, stop, context)
|
|
|
5249
5253
|
}
|
|
5250
5254
|
}
|
|
5251
5255
|
function plainCallTarget(expression) {
|
|
5252
|
-
if (
|
|
5256
|
+
if (ts8.isIdentifier(expression))
|
|
5253
5257
|
return true;
|
|
5254
|
-
if (
|
|
5258
|
+
if (ts8.isParenthesizedExpression(expression))
|
|
5255
5259
|
return plainCallTarget(expression.expression);
|
|
5256
|
-
return
|
|
5260
|
+
return ts8.isPropertyAccessExpression(expression) && expression.questionDotToken == null && plainCallTarget(expression.expression);
|
|
5257
5261
|
}
|
|
5258
5262
|
function lowerTopLevelDeclarations(statement, context, scan) {
|
|
5259
5263
|
for (const declarator of statement.declarationList.declarations) {
|
|
5260
5264
|
if (declarator.initializer == null)
|
|
5261
5265
|
throw new LoweringStop(declarator, { kind: "variableDeclarationShape" });
|
|
5262
|
-
if (
|
|
5266
|
+
if (ts8.isObjectBindingPattern(declarator.name)) {
|
|
5263
5267
|
const source = lowerExpression(declarator.initializer, context);
|
|
5264
5268
|
for (const element of declarator.name.elements) {
|
|
5265
|
-
if (!
|
|
5269
|
+
if (!ts8.isIdentifier(element.name) || element.dotDotDotToken != null || element.initializer != null) {
|
|
5266
5270
|
throw new LoweringStop(element, { kind: "variableDeclarationShape" });
|
|
5267
5271
|
}
|
|
5268
|
-
const property = element.propertyName == null ? element.name.text :
|
|
5272
|
+
const property = element.propertyName == null ? element.name.text : ts8.isIdentifier(element.propertyName) ? element.propertyName.text : null;
|
|
5269
5273
|
if (property == null)
|
|
5270
5274
|
throw new LoweringStop(element, { kind: "variableDeclarationShape" });
|
|
5271
5275
|
const elementType = context.checker.getTypeAtLocation(element.name);
|
|
@@ -5281,14 +5285,14 @@ function lowerTopLevelDeclarations(statement, context, scan) {
|
|
|
5281
5285
|
}
|
|
5282
5286
|
continue;
|
|
5283
5287
|
}
|
|
5284
|
-
if (!
|
|
5288
|
+
if (!ts8.isIdentifier(declarator.name)) {
|
|
5285
5289
|
throw new LoweringStop(declarator, { kind: "variableDeclarationShape" });
|
|
5286
5290
|
}
|
|
5287
5291
|
const symbol = context.checker.getSymbolAtLocation(declarator.name);
|
|
5288
5292
|
const binding = symbol == null ? undefined : scan.bindingsBySymbol.get(symbol);
|
|
5289
5293
|
if (binding == null)
|
|
5290
5294
|
throw new LoweringStop(declarator, { kind: "variableDeclarationShape" });
|
|
5291
|
-
if ((statement.declarationList.flags &
|
|
5295
|
+
if ((statement.declarationList.flags & ts8.NodeFlags.Const) !== 0 && directFunctionExpression(declarator.initializer) != null) {
|
|
5292
5296
|
const marker = addInstruction(context, declarator.initializer, { kind: "opaqueConstant" });
|
|
5293
5297
|
addInstruction(context, declarator, { kind: "moduleWrite", binding, value: marker });
|
|
5294
5298
|
continue;
|
|
@@ -5298,15 +5302,15 @@ function lowerTopLevelDeclarations(statement, context, scan) {
|
|
|
5298
5302
|
}
|
|
5299
5303
|
}
|
|
5300
5304
|
function skippedAtTopLevel(statement) {
|
|
5301
|
-
return
|
|
5305
|
+
return ts8.isFunctionDeclaration(statement) && statement.name != null || ts8.isImportDeclaration(statement) || ts8.isTypeAliasDeclaration(statement) || ts8.isInterfaceDeclaration(statement) || ts8.isExportDeclaration(statement);
|
|
5302
5306
|
}
|
|
5303
5307
|
function scanSkippedModuleEffects(root, checker, bindingsBySymbol, bindings) {
|
|
5304
5308
|
const directWrites = [];
|
|
5305
5309
|
let invokesUnknownCode = false;
|
|
5306
5310
|
const visit = (node) => {
|
|
5307
5311
|
demoteModuleWritesInNode(node, checker, bindingsBySymbol, bindings, directWrites);
|
|
5308
|
-
invokesUnknownCode ||=
|
|
5309
|
-
if (
|
|
5312
|
+
invokesUnknownCode ||= ts8.isCallExpression(node) || ts8.isNewExpression(node) || ts8.isTaggedTemplateExpression(node) || ts8.isAwaitExpression(node) || ts8.isYieldExpression(node) || ts8.isForOfStatement(node) || ts8.isSpreadElement(node) || ts8.isArrayBindingPattern(node) || ts8.isVariableDeclarationList(node) && (node.flags & ts8.NodeFlags.Using) !== 0 || ts8.isBinaryExpression(node) && (node.operatorToken.kind === ts8.SyntaxKind.InstanceOfKeyword || node.operatorToken.kind === ts8.SyntaxKind.EqualsToken && containsArrayLiteral(node.left)) || ts8.isJsxElement(node) || ts8.isJsxSelfClosingElement(node) || ts8.isJsxFragment(node) || ts8.isClassDeclaration(node) || ts8.isClassExpression(node);
|
|
5313
|
+
if (ts8.isVariableDeclaration(node) && ts8.isIdentifier(node.name)) {
|
|
5310
5314
|
const symbol = checker.getSymbolAtLocation(node.name);
|
|
5311
5315
|
const binding = symbol == null ? undefined : bindingsBySymbol.get(symbol);
|
|
5312
5316
|
if (binding != null) {
|
|
@@ -5328,7 +5332,7 @@ function declaredRecordProperties(type, checker, seen) {
|
|
|
5328
5332
|
return null;
|
|
5329
5333
|
const properties = [];
|
|
5330
5334
|
for (const property of checker.getPropertiesOfType(type)) {
|
|
5331
|
-
const optional = (property.flags &
|
|
5335
|
+
const optional = (property.flags & ts8.SymbolFlags.Optional) !== 0;
|
|
5332
5336
|
const walked = declaredKind(checker.getTypeOfSymbol(property), checker, [...seen, type]);
|
|
5333
5337
|
const opaqueLeaf = { kind: "opaque" };
|
|
5334
5338
|
const propertyDeclared = declaredOnlyInDeclarationFiles(property) ? opaqueLeaf : walked ?? opaqueLeaf;
|
|
@@ -5434,14 +5438,14 @@ function declaredKindUncached(type, checker, seen) {
|
|
|
5434
5438
|
}
|
|
5435
5439
|
if (inner == null)
|
|
5436
5440
|
return null;
|
|
5437
|
-
const admitsNull = type.types.some((member) => (member.flags &
|
|
5438
|
-
const admitsUndefined = type.types.some((member) => (member.flags &
|
|
5441
|
+
const admitsNull = type.types.some((member) => (member.flags & ts8.TypeFlags.Null) !== 0);
|
|
5442
|
+
const admitsUndefined = type.types.some((member) => (member.flags & ts8.TypeFlags.Undefined) !== 0);
|
|
5439
5443
|
return { kind: "nullish", inner, sentinels: admitsNull && admitsUndefined ? "both" : admitsNull ? "null" : "undefined" };
|
|
5440
5444
|
}
|
|
5441
5445
|
case "opaque":
|
|
5442
5446
|
return { kind: "opaque" };
|
|
5443
5447
|
case "array": {
|
|
5444
|
-
const element = checker.getIndexTypeOfType(type,
|
|
5448
|
+
const element = checker.getIndexTypeOfType(type, ts8.IndexKind.Number);
|
|
5445
5449
|
if (element == null)
|
|
5446
5450
|
return null;
|
|
5447
5451
|
const elementKind = declaredKind(element, checker, [...seen, type]);
|
|
@@ -5493,13 +5497,14 @@ function declaredKindUncached(type, checker, seen) {
|
|
|
5493
5497
|
}
|
|
5494
5498
|
function numericLiteralInterval(type) {
|
|
5495
5499
|
const members = type.isUnion() ? type.types : [type];
|
|
5496
|
-
if (!members.every((member) => (member.flags & ts7.TypeFlags.NumberLiteral) !== 0 && (member.flags & ts7.TypeFlags.EnumLiteral) === 0))
|
|
5497
|
-
return null;
|
|
5498
5500
|
let lower = Infinity;
|
|
5499
5501
|
let upper = -Infinity;
|
|
5500
5502
|
let integer = true;
|
|
5501
5503
|
for (const member of members) {
|
|
5502
|
-
const
|
|
5504
|
+
const number = numberConstituent(member);
|
|
5505
|
+
if (number == null || (number.flags & ts8.TypeFlags.NumberLiteral) === 0 || (number.flags & ts8.TypeFlags.EnumLiteral) !== 0)
|
|
5506
|
+
return null;
|
|
5507
|
+
const value2 = number.value;
|
|
5503
5508
|
if (!Number.isFinite(value2))
|
|
5504
5509
|
return "nonFinite";
|
|
5505
5510
|
lower = Math.min(lower, value2);
|
|
@@ -5546,7 +5551,7 @@ function joinScalarDeclaredKinds(members) {
|
|
|
5546
5551
|
function tupleHasOptionalOrRestPositions(type, checker) {
|
|
5547
5552
|
if (!checker.isTupleType(type))
|
|
5548
5553
|
return false;
|
|
5549
|
-
return type.target.elementFlags.some((flags) => (flags &
|
|
5554
|
+
return type.target.elementFlags.some((flags) => (flags & ts8.ElementFlags.Required) === 0);
|
|
5550
5555
|
}
|
|
5551
5556
|
function demote(bindings, binding) {
|
|
5552
5557
|
const category = bindings[binding].category;
|
|
@@ -5568,21 +5573,21 @@ function demote(bindings, binding) {
|
|
|
5568
5573
|
}
|
|
5569
5574
|
|
|
5570
5575
|
// src/lower/static-intrinsics.ts
|
|
5571
|
-
import * as
|
|
5576
|
+
import * as ts9 from "typescript";
|
|
5572
5577
|
function scanStaticAnnotations(sourceFile, functions, checker) {
|
|
5573
5578
|
const ownerIndex = new Map(functions.map((unit, index) => [unit.declaration, index]));
|
|
5574
5579
|
const callsByFunction = functions.map(() => []);
|
|
5575
5580
|
const outsideTopLevelFunctions = [];
|
|
5576
5581
|
const visit = (node) => {
|
|
5577
|
-
if (
|
|
5578
|
-
const owner =
|
|
5582
|
+
if (ts9.isCallExpression(node) && isStaticIntent(node, checker)) {
|
|
5583
|
+
const owner = ts9.findAncestor(node, ts9.isFunctionLike);
|
|
5579
5584
|
const index = owner == null ? undefined : ownerIndex.get(owner);
|
|
5580
5585
|
if (index == null)
|
|
5581
5586
|
outsideTopLevelFunctions.push(node);
|
|
5582
5587
|
else
|
|
5583
5588
|
callsByFunction[index].push(node);
|
|
5584
5589
|
}
|
|
5585
|
-
|
|
5590
|
+
ts9.forEachChild(node, visit);
|
|
5586
5591
|
};
|
|
5587
5592
|
visit(sourceFile);
|
|
5588
5593
|
return {
|
|
@@ -5590,9 +5595,9 @@ function scanStaticAnnotations(sourceFile, functions, checker) {
|
|
|
5590
5595
|
const calls = callsByFunction[index];
|
|
5591
5596
|
const callSet = new Set(calls);
|
|
5592
5597
|
const leading = new Set;
|
|
5593
|
-
if (unit.declaration.body != null &&
|
|
5598
|
+
if (unit.declaration.body != null && ts9.isBlock(unit.declaration.body)) {
|
|
5594
5599
|
for (const statement of unit.declaration.body.statements) {
|
|
5595
|
-
if (!
|
|
5600
|
+
if (!ts9.isExpressionStatement(statement) || !ts9.isCallExpression(statement.expression) || !callSet.has(statement.expression))
|
|
5596
5601
|
break;
|
|
5597
5602
|
leading.add(statement.expression);
|
|
5598
5603
|
}
|
|
@@ -5606,29 +5611,30 @@ function annotationForCall(call, role) {
|
|
|
5606
5611
|
if (call.arguments.length !== 1) {
|
|
5607
5612
|
return { kind: "invalid", call, role, node: call, problem: "argumentCount" };
|
|
5608
5613
|
}
|
|
5609
|
-
if (!
|
|
5614
|
+
if (!ts9.isExpressionStatement(call.parent) || call.parent.expression !== call) {
|
|
5610
5615
|
return { kind: "invalid", call, role, node: call, problem: "position" };
|
|
5611
5616
|
}
|
|
5612
5617
|
const callee = call.expression;
|
|
5613
|
-
if (call.questionDotToken != null ||
|
|
5618
|
+
if (call.questionDotToken != null || ts9.isPropertyAccessExpression(callee) && callee.questionDotToken != null) {
|
|
5614
5619
|
return { kind: "invalid", call, role, node: call, problem: "optionalCall" };
|
|
5615
5620
|
}
|
|
5616
5621
|
return { kind: "valid", call, role, condition: call.arguments[0] };
|
|
5617
5622
|
}
|
|
5618
5623
|
function isStaticIntent(call, checker) {
|
|
5619
|
-
if (!
|
|
5624
|
+
if (!ts9.isPropertyAccessExpression(call.expression))
|
|
5620
5625
|
return false;
|
|
5621
5626
|
const access = call.expression;
|
|
5622
|
-
if (!
|
|
5627
|
+
if (!ts9.isIdentifier(access.expression) || access.expression.text !== "console" || access.name.text !== "assert")
|
|
5623
5628
|
return false;
|
|
5624
5629
|
const resolved = checker.getSymbolAtLocation(access.expression);
|
|
5625
|
-
const globalConsole = checker.resolveName("console", undefined,
|
|
5630
|
+
const globalConsole = checker.resolveName("console", undefined, ts9.SymbolFlags.Value, false);
|
|
5626
5631
|
return resolved != null && resolved === globalConsole;
|
|
5627
5632
|
}
|
|
5628
5633
|
|
|
5629
5634
|
// src/lower/program.ts
|
|
5630
5635
|
function lowerSource(checked, baseDirectory = process.cwd()) {
|
|
5631
|
-
const { sourceFile,
|
|
5636
|
+
const { sourceFile, program } = checked;
|
|
5637
|
+
const checker = program.getTypeChecker();
|
|
5632
5638
|
const declarations = topLevelFunctionUnits(sourceFile);
|
|
5633
5639
|
const staticScan = scanStaticAnnotations(sourceFile, declarations, checker);
|
|
5634
5640
|
const recordStaticAnnotationIssues = (sites2) => staticScan.outsideTopLevelFunctions.map((call) => {
|
|
@@ -5699,7 +5705,7 @@ function lowerSource(checked, baseDirectory = process.cwd()) {
|
|
|
5699
5705
|
const declaration = topLevelFunctions[index];
|
|
5700
5706
|
const staticAnnotations = staticScan.functions[index];
|
|
5701
5707
|
try {
|
|
5702
|
-
functions.push(lowerFunction(declaration, staticAnnotations, sourceFile, checker, functionsBySymbol, scan, sites));
|
|
5708
|
+
functions.push(lowerFunction(declaration, staticAnnotations, sourceFile, checker, program, functionsBySymbol, scan, sites));
|
|
5703
5709
|
} catch (error) {
|
|
5704
5710
|
if (!(error instanceof LoweringStop))
|
|
5705
5711
|
throw error;
|
|
@@ -5713,7 +5719,7 @@ function lowerSource(checked, baseDirectory = process.cwd()) {
|
|
|
5713
5719
|
});
|
|
5714
5720
|
}
|
|
5715
5721
|
}
|
|
5716
|
-
const { initializer, skips } = lowerModuleInitializer(sourceFile, checker, functionsBySymbol, scan, sites);
|
|
5722
|
+
const { initializer, skips } = lowerModuleInitializer(sourceFile, checker, program, functionsBySymbol, scan, sites);
|
|
5717
5723
|
return {
|
|
5718
5724
|
file: sourceFile.fileName,
|
|
5719
5725
|
baseDirectory,
|
|
@@ -5726,7 +5732,7 @@ function lowerSource(checked, baseDirectory = process.cwd()) {
|
|
|
5726
5732
|
initializerSkips: skips
|
|
5727
5733
|
};
|
|
5728
5734
|
}
|
|
5729
|
-
function lowerFunction(unit, staticAnnotations, sourceFile, checker, functionsBySymbol, scan, sites) {
|
|
5735
|
+
function lowerFunction(unit, staticAnnotations, sourceFile, checker, program, functionsBySymbol, scan, sites) {
|
|
5730
5736
|
const { declaration } = unit;
|
|
5731
5737
|
for (const annotation of staticAnnotations) {
|
|
5732
5738
|
if (annotation.kind === "invalid") {
|
|
@@ -5735,7 +5741,7 @@ function lowerFunction(unit, staticAnnotations, sourceFile, checker, functionsBy
|
|
|
5735
5741
|
}
|
|
5736
5742
|
if (declaration.body == null)
|
|
5737
5743
|
throw unsupported(declaration, { kind: "functionWithoutBody" });
|
|
5738
|
-
if (!
|
|
5744
|
+
if (!ts10.isArrowFunction(declaration) && declaration.asteriskToken != null || declaration.modifiers?.some((modifier) => modifier.kind === ts10.SyntaxKind.AsyncKeyword) === true) {
|
|
5739
5745
|
throw unsupported(declaration, { kind: "asyncOrGeneratorFunction" });
|
|
5740
5746
|
}
|
|
5741
5747
|
assertAccepted(declaration);
|
|
@@ -5745,20 +5751,17 @@ function lowerFunction(unit, staticAnnotations, sourceFile, checker, functionsBy
|
|
|
5745
5751
|
kind: unit.initializer == null ? "functionWithoutSignature" : "constFunctionSignature"
|
|
5746
5752
|
});
|
|
5747
5753
|
}
|
|
5748
|
-
if (checker.getTypePredicateOfSignature(signature) != null) {
|
|
5749
|
-
throw unsupported(declaration, { kind: "typePredicate" });
|
|
5750
|
-
}
|
|
5751
5754
|
const returnType = checker.getReturnTypeOfSignature(signature);
|
|
5752
|
-
const returnsVoid = (returnType.flags & (
|
|
5755
|
+
const returnsVoid = (returnType.flags & (ts10.TypeFlags.Void | ts10.TypeFlags.Undefined | ts10.TypeFlags.Never)) !== 0;
|
|
5753
5756
|
if (!returnsVoid && valueKind(returnType, checker) == null) {
|
|
5754
5757
|
throw unsupported(declaration.type ?? declaration, { kind: "valueType", typeText: checker.typeToString(returnType) });
|
|
5755
5758
|
}
|
|
5756
|
-
const context = createFunctionContext(sourceFile, checker, functionsBySymbol, scan.bindingsBySymbol, sites, staticAnnotations, returnsVoid);
|
|
5759
|
+
const context = createFunctionContext(sourceFile, checker, program, functionsBySymbol, scan.bindingsBySymbol, sites, staticAnnotations, returnsVoid);
|
|
5757
5760
|
const entry = context.currentBlock;
|
|
5758
5761
|
for (let parameterIndex = 0;parameterIndex < declaration.parameters.length; parameterIndex++) {
|
|
5759
5762
|
const parameter = declaration.parameters[parameterIndex];
|
|
5760
5763
|
const parameterType = unit.initializer == null ? checker.getTypeAtLocation(parameter) : checker.getTypeOfSymbolAtLocation(signature.parameters[parameterIndex], signature.declaration);
|
|
5761
|
-
if (
|
|
5764
|
+
if (ts10.isObjectBindingPattern(parameter.name)) {
|
|
5762
5765
|
const type2 = lowerParameterType(parameter, parameterType, checker);
|
|
5763
5766
|
const patternName = parameter.name.getText(sourceFile).replace(/\s+/g, " ");
|
|
5764
5767
|
if (parameter.initializer != null) {
|
|
@@ -5768,10 +5771,10 @@ function lowerFunction(unit, staticAnnotations, sourceFile, checker, functionsBy
|
|
|
5768
5771
|
const bindings = [];
|
|
5769
5772
|
context.parameters.push({ value: value3, name: patternName, type: type2, site: addSite(context, parameter), bindings });
|
|
5770
5773
|
for (const element of parameter.name.elements) {
|
|
5771
|
-
if (!
|
|
5774
|
+
if (!ts10.isIdentifier(element.name) || element.dotDotDotToken != null || element.initializer != null) {
|
|
5772
5775
|
throw unsupported(element, { kind: "destructuredParameter" });
|
|
5773
5776
|
}
|
|
5774
|
-
const property = element.propertyName == null ? element.name.text :
|
|
5777
|
+
const property = element.propertyName == null ? element.name.text : ts10.isIdentifier(element.propertyName) ? element.propertyName.text : null;
|
|
5775
5778
|
if (property == null)
|
|
5776
5779
|
throw unsupported(element, { kind: "destructuredParameter" });
|
|
5777
5780
|
bindings.push({ property, local: element.name.text });
|
|
@@ -5787,7 +5790,7 @@ function lowerFunction(unit, staticAnnotations, sourceFile, checker, functionsBy
|
|
|
5787
5790
|
}
|
|
5788
5791
|
continue;
|
|
5789
5792
|
}
|
|
5790
|
-
if (!
|
|
5793
|
+
if (!ts10.isIdentifier(parameter.name))
|
|
5791
5794
|
throw unsupported(parameter.name, { kind: "destructuredParameter" });
|
|
5792
5795
|
if (parameter.dotDotDotToken != null) {
|
|
5793
5796
|
throw unsupported(parameter, { kind: "parameterType", typeText: `...${checker.typeToString(checker.getTypeAtLocation(parameter))}`, optionalOrRestTuple: false });
|
|
@@ -5805,7 +5808,7 @@ function lowerFunction(unit, staticAnnotations, sourceFile, checker, functionsBy
|
|
|
5805
5808
|
context.parameters.push({ value: value2, name: parameter.name.text, type, site: addSite(context, parameter), bindings: null });
|
|
5806
5809
|
}
|
|
5807
5810
|
lowerFiniteInputRequirements(context);
|
|
5808
|
-
if (
|
|
5811
|
+
if (ts10.isBlock(declaration.body)) {
|
|
5809
5812
|
lowerStatements(declaration.body.statements, context);
|
|
5810
5813
|
} else {
|
|
5811
5814
|
const value2 = lowerExpression(declaration.body, context);
|
|
@@ -5863,7 +5866,7 @@ function declaredRecordReturnNames(returnType, checker) {
|
|
|
5863
5866
|
if (kind === "object")
|
|
5864
5867
|
return checker.getPropertiesOfType(returnType).map((property) => property.name);
|
|
5865
5868
|
if (kind === "nullable" && returnType.isUnion()) {
|
|
5866
|
-
const missing =
|
|
5869
|
+
const missing = ts10.TypeFlags.Null | ts10.TypeFlags.Undefined;
|
|
5867
5870
|
const members = returnType.types.filter((member) => (member.flags & missing) === 0);
|
|
5868
5871
|
if (members.length > 0 && members.every((member) => valueKind(member, checker) === "object")) {
|
|
5869
5872
|
const names = new Set;
|
|
@@ -6730,14 +6733,10 @@ function formatUnsupportedReason(reason) {
|
|
|
6730
6733
|
return "object spread (list every field explicitly, e.g. {gain: config.gain})";
|
|
6731
6734
|
case "asyncOrGeneratorFunction":
|
|
6732
6735
|
return "an async or generator function (the runtime result is a Promise or iterator, not the body's return value)";
|
|
6733
|
-
case "typePredicate":
|
|
6734
|
-
return "a type predicate (the checker takes the predicate on faith; return a plain boolean and check properties where they are read)";
|
|
6735
6736
|
case "protoProperty":
|
|
6736
6737
|
return "a property named __proto__ (prototype-setting syntax at runtime, not a data property)";
|
|
6737
6738
|
case "enumMemberRead":
|
|
6738
6739
|
return "an enum member read (replace the enum with plain module consts, e.g. const directionUp = 1)";
|
|
6739
|
-
case "prototypeMemberRead":
|
|
6740
|
-
return `read of the inherited prototype member ${reason.property} (records carry only their own data properties)`;
|
|
6741
6740
|
case "binaryOperator":
|
|
6742
6741
|
return reason.operator === "in" ? "the `in` operator (use a distinct string or boolean tag when property presence distinguishes union variants)" : `binary operator ${reason.operator} (supported: + - * / %, comparisons, and boolean && || !)`;
|
|
6743
6742
|
case "call":
|
|
@@ -6937,7 +6936,7 @@ function formatNumber(value2) {
|
|
|
6937
6936
|
}
|
|
6938
6937
|
|
|
6939
6938
|
// src/typescript/diagnostics.ts
|
|
6940
|
-
import * as
|
|
6939
|
+
import * as ts11 from "typescript";
|
|
6941
6940
|
|
|
6942
6941
|
class TypeScriptDiagnosticsError extends Error {
|
|
6943
6942
|
diagnostics;
|
|
@@ -6954,10 +6953,10 @@ class TypeScriptDiagnosticsError extends Error {
|
|
|
6954
6953
|
function formatTypeScriptDiagnostics(diagnostics, options, currentDirectory) {
|
|
6955
6954
|
const host = {
|
|
6956
6955
|
getCurrentDirectory: () => currentDirectory,
|
|
6957
|
-
getCanonicalFileName:
|
|
6958
|
-
getNewLine: () =>
|
|
6956
|
+
getCanonicalFileName: ts11.sys.useCaseSensitiveFileNames ? (file) => file : (file) => file.toLowerCase(),
|
|
6957
|
+
getNewLine: () => ts11.sys.newLine
|
|
6959
6958
|
};
|
|
6960
|
-
return usePrettyOutput(options["pretty"]) ?
|
|
6959
|
+
return usePrettyOutput(options["pretty"]) ? ts11.formatDiagnosticsWithColorAndContext(diagnostics, host) : ts11.formatDiagnostics(diagnostics, host);
|
|
6961
6960
|
}
|
|
6962
6961
|
function usePrettyOutput(configured) {
|
|
6963
6962
|
if (typeof configured === "boolean")
|
|
@@ -6968,7 +6967,7 @@ function usePrettyOutput(configured) {
|
|
|
6968
6967
|
const forceColor = process.env["FORCE_COLOR"];
|
|
6969
6968
|
if (forceColor != null && forceColor !== "")
|
|
6970
6969
|
return true;
|
|
6971
|
-
return
|
|
6970
|
+
return ts11.sys.writeOutputIsTTY?.() === true;
|
|
6972
6971
|
}
|
|
6973
6972
|
function color(code, text) {
|
|
6974
6973
|
return `\x1B[${code}m${text}\x1B[0m`;
|
|
@@ -7300,10 +7299,8 @@ function guidesForUnsupportedReason(reason) {
|
|
|
7300
7299
|
case "computedPropertyName":
|
|
7301
7300
|
case "objectSpread":
|
|
7302
7301
|
case "asyncOrGeneratorFunction":
|
|
7303
|
-
case "typePredicate":
|
|
7304
7302
|
case "protoProperty":
|
|
7305
7303
|
case "enumMemberRead":
|
|
7306
|
-
case "prototypeMemberRead":
|
|
7307
7304
|
case "binaryOperator":
|
|
7308
7305
|
case "callWithFewerArguments":
|
|
7309
7306
|
case "callWithMoreArguments":
|
|
@@ -7361,12 +7358,12 @@ function isCallerInput(expression) {
|
|
|
7361
7358
|
|
|
7362
7359
|
// src/typescript/check.ts
|
|
7363
7360
|
import { resolve } from "node:path";
|
|
7364
|
-
import * as
|
|
7361
|
+
import * as ts12 from "typescript";
|
|
7365
7362
|
var fallbackOptions = {
|
|
7366
|
-
target:
|
|
7367
|
-
module:
|
|
7368
|
-
moduleResolution:
|
|
7369
|
-
moduleDetection:
|
|
7363
|
+
target: ts12.ScriptTarget.ESNext,
|
|
7364
|
+
module: ts12.ModuleKind.ESNext,
|
|
7365
|
+
moduleResolution: ts12.ModuleResolutionKind.Bundler,
|
|
7366
|
+
moduleDetection: ts12.ModuleDetectionKind.Force,
|
|
7370
7367
|
strict: true,
|
|
7371
7368
|
noUncheckedIndexedAccess: true,
|
|
7372
7369
|
exactOptionalPropertyTypes: true,
|
|
@@ -7376,25 +7373,25 @@ var fallbackOptions = {
|
|
|
7376
7373
|
};
|
|
7377
7374
|
function checkFile(file) {
|
|
7378
7375
|
const absoluteFile = resolve(file);
|
|
7379
|
-
const program =
|
|
7376
|
+
const program = ts12.createProgram([absoluteFile], fallbackOptions);
|
|
7380
7377
|
return checkedSource(program, absoluteFile, fallbackOptions);
|
|
7381
7378
|
}
|
|
7382
7379
|
function checkedSource(program, file, options) {
|
|
7383
|
-
const diagnostics =
|
|
7380
|
+
const diagnostics = ts12.getPreEmitDiagnostics(program);
|
|
7384
7381
|
if (diagnostics.length > 0) {
|
|
7385
7382
|
throw new TypeScriptDiagnosticsError(diagnostics, options, process.cwd());
|
|
7386
7383
|
}
|
|
7387
7384
|
const sourceFile = program.getSourceFile(file);
|
|
7388
7385
|
if (sourceFile == null)
|
|
7389
7386
|
throw new Error(`TypeScript did not load ${file}`);
|
|
7390
|
-
return { sourceFile,
|
|
7387
|
+
return { sourceFile, program };
|
|
7391
7388
|
}
|
|
7392
7389
|
|
|
7393
7390
|
// src/typescript/project.ts
|
|
7394
7391
|
import { dirname, isAbsolute, relative as relative2, resolve as resolve2, sep } from "node:path";
|
|
7395
|
-
import * as
|
|
7392
|
+
import * as ts13 from "typescript";
|
|
7396
7393
|
function findTypeScriptConfig(searchFrom) {
|
|
7397
|
-
return
|
|
7394
|
+
return ts13.findConfigFile(resolve2(searchFrom), (file) => ts13.sys.fileExists(file), "tsconfig.json") ?? null;
|
|
7398
7395
|
}
|
|
7399
7396
|
function loadTypeScriptProjectGraph(configPath) {
|
|
7400
7397
|
const loaded = [];
|
|
@@ -7411,8 +7408,8 @@ function loadTypeScriptProjectGraph(configPath) {
|
|
|
7411
7408
|
const parsed = parseConfig(absoluteConfigPath);
|
|
7412
7409
|
requireStrictNullChecks(parsed.options, absoluteConfigPath);
|
|
7413
7410
|
for (const reference of parsed.projectReferences ?? [])
|
|
7414
|
-
load(
|
|
7415
|
-
const program =
|
|
7411
|
+
load(ts13.resolveProjectReferencePath(reference));
|
|
7412
|
+
const program = ts13.createProgram({
|
|
7416
7413
|
rootNames: parsed.fileNames,
|
|
7417
7414
|
options: parsed.options,
|
|
7418
7415
|
configFileParsingDiagnostics: parsed.errors,
|
|
@@ -7447,8 +7444,8 @@ function projectSources(projects) {
|
|
|
7447
7444
|
return [...sources.values()].sort((left, right) => left.sourceFile.fileName.localeCompare(right.sourceFile.fileName));
|
|
7448
7445
|
}
|
|
7449
7446
|
function parseConfig(configPath) {
|
|
7450
|
-
const parsed =
|
|
7451
|
-
...
|
|
7447
|
+
const parsed = ts13.getParsedCommandLineOfConfigFile(configPath, undefined, {
|
|
7448
|
+
...ts13.sys,
|
|
7452
7449
|
onUnRecoverableConfigFileDiagnostic: (diagnostic) => {
|
|
7453
7450
|
throw new TypeScriptDiagnosticsError([diagnostic], {}, dirname(configPath));
|
|
7454
7451
|
}
|
|
@@ -7509,7 +7506,7 @@ function analyzeProject(searchFrom) {
|
|
|
7509
7506
|
const projects = loadTypeScriptProjectGraph(configPath);
|
|
7510
7507
|
const rootProject = projects.at(-1);
|
|
7511
7508
|
const sources = projectSources(projects);
|
|
7512
|
-
const diagnostics = uniqueDiagnostics(projects.flatMap((project) =>
|
|
7509
|
+
const diagnostics = uniqueDiagnostics(projects.flatMap((project) => ts14.getPreEmitDiagnostics(project.program)));
|
|
7513
7510
|
requireNoTypeScriptErrors(diagnostics, rootProject.parsed.options);
|
|
7514
7511
|
const files = [];
|
|
7515
7512
|
let analyzed = 0;
|
|
@@ -7746,7 +7743,7 @@ function analyzeTargetFile(file) {
|
|
|
7746
7743
|
if (source == null) {
|
|
7747
7744
|
throw new Error(`File is not part of the project resolved from ${configPath}: ${absoluteFile}`);
|
|
7748
7745
|
}
|
|
7749
|
-
const diagnostics =
|
|
7746
|
+
const diagnostics = ts14.getPreEmitDiagnostics(source.project.program, source.sourceFile);
|
|
7750
7747
|
requireNoTypeScriptErrors(diagnostics, rootProject.parsed.options);
|
|
7751
7748
|
return {
|
|
7752
7749
|
detailed: analyzeProjectSource(source, process.cwd()),
|
|
@@ -7755,7 +7752,7 @@ function analyzeTargetFile(file) {
|
|
|
7755
7752
|
}
|
|
7756
7753
|
function canonicalFilePath(file) {
|
|
7757
7754
|
const real = realpathSync.native(file);
|
|
7758
|
-
return
|
|
7755
|
+
return ts14.sys.useCaseSensitiveFileNames ? real : real.toLowerCase();
|
|
7759
7756
|
}
|
|
7760
7757
|
function analyzeFileAlone(absoluteFile) {
|
|
7761
7758
|
return {
|
|
@@ -7766,13 +7763,13 @@ function analyzeFileAlone(absoluteFile) {
|
|
|
7766
7763
|
function analyzeProjectSource(source, reportBaseDirectory) {
|
|
7767
7764
|
return analyzeCheckedSource({
|
|
7768
7765
|
sourceFile: source.sourceFile,
|
|
7769
|
-
|
|
7766
|
+
program: source.project.program
|
|
7770
7767
|
}, reportBaseDirectory);
|
|
7771
7768
|
}
|
|
7772
7769
|
function uniqueDiagnostics(diagnostics) {
|
|
7773
7770
|
const seen = new Set;
|
|
7774
7771
|
return diagnostics.filter((diagnostic) => {
|
|
7775
|
-
const message =
|
|
7772
|
+
const message = ts14.flattenDiagnosticMessageText(diagnostic.messageText, `
|
|
7776
7773
|
`);
|
|
7777
7774
|
const key = `${diagnostic.file?.fileName ?? ""}:${diagnostic.start ?? ""}:${diagnostic.length ?? ""}:${diagnostic.code}:${message}`;
|
|
7778
7775
|
if (seen.has(key))
|
|
@@ -7793,7 +7790,7 @@ function requireNoTypeScriptErrors(diagnostics, options) {
|
|
|
7793
7790
|
printTypeScriptDiagnostics(diagnostics, options, process.cwd());
|
|
7794
7791
|
}
|
|
7795
7792
|
function hasErrorDiagnostics(diagnostics) {
|
|
7796
|
-
return diagnostics.some((diagnostic) => diagnostic.category ===
|
|
7793
|
+
return diagnostics.some((diagnostic) => diagnostic.category === ts14.DiagnosticCategory.Error);
|
|
7797
7794
|
}
|
|
7798
7795
|
|
|
7799
7796
|
// fr.ts
|