Skip to content

Commit c7b65ac

Browse files
Merge branch 'main' into regex-recovery
2 parents ff858bc + 9504b75 commit c7b65ac

File tree

66 files changed

+2190
-815
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+2190
-815
lines changed

.eslintrc.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
"varsIgnorePattern": "^(_+$|_[^_])"
128128
}
129129
],
130+
"@typescript-eslint/no-inferrable-types": "off",
130131

131132
// Pending https://github.com/typescript-eslint/typescript-eslint/issues/4820
132133
"@typescript-eslint/prefer-optional-chain": "off",

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ jobs:
2929
- windows-latest
3030
- macos-14
3131
node-version:
32+
- '22'
3233
- '20'
3334
- '18'
3435
- '16'

src/compiler/checker.ts

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ import {
102102
countWhere,
103103
createBinaryExpressionTrampoline,
104104
createCompilerDiagnostic,
105+
createDetachedDiagnostic,
105106
createDiagnosticCollection,
106107
createDiagnosticForFileFromMessageChain,
107108
createDiagnosticForNode,
@@ -123,6 +124,7 @@ import {
123124
createPrinterWithRemoveCommentsNeverAsciiEscape,
124125
createPrinterWithRemoveCommentsOmitTrailingSemicolon,
125126
createPropertyNameNodeForIdentifierOrLiteral,
127+
createScanner,
126128
createSymbolTable,
127129
createSyntacticTypeNodeBuilder,
128130
createTextWriter,
@@ -937,6 +939,7 @@ import {
937939
rangeOfTypeParameters,
938940
ReadonlyKeyword,
939941
reduceLeft,
942+
RegularExpressionLiteral,
940943
RelationComparisonResult,
941944
relativeComplement,
942945
removeExtension,
@@ -953,6 +956,7 @@ import {
953956
ReverseMappedType,
954957
sameMap,
955958
SatisfiesExpression,
959+
Scanner,
956960
scanTokenAtPosition,
957961
ScriptKind,
958962
ScriptTarget,
@@ -1446,6 +1450,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
14461450
var requestedExternalEmitHelperNames = new Set<string>();
14471451
var requestedExternalEmitHelpers: ExternalEmitHelpers;
14481452
var externalHelpersModule: Symbol;
1453+
var scanner: Scanner | undefined;
14491454

14501455
var Symbol = objectAllocator.getSymbolConstructor();
14511456
var Type = objectAllocator.getTypeConstructor();
@@ -6689,7 +6694,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
66896694
if (!nodeIsSynthesized(node) && getParseTreeNode(node) === node) {
66906695
return node;
66916696
}
6692-
return setTextRange(context, factory.cloneNode(visitEachChild(node, deepCloneOrReuseNode, /*context*/ undefined, deepCloneOrReuseNodes)), node);
6697+
return setTextRange(context, factory.cloneNode(visitEachChild(node, deepCloneOrReuseNode, /*context*/ undefined, deepCloneOrReuseNodes, deepCloneOrReuseNode)), node);
66936698
}
66946699

66956700
function deepCloneOrReuseNodes(
@@ -31353,6 +31358,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3135331358
}
3135431359
}
3135531360

31361+
function checkGrammarRegularExpressionLiteral(node: RegularExpressionLiteral) {
31362+
const sourceFile = getSourceFileOfNode(node);
31363+
if (!hasParseDiagnostics(sourceFile)) {
31364+
let lastError: DiagnosticWithLocation | undefined;
31365+
scanner ??= createScanner(ScriptTarget.ESNext, /*skipTrivia*/ true);
31366+
scanner.setScriptTarget(sourceFile.languageVersion);
31367+
scanner.setLanguageVariant(sourceFile.languageVariant);
31368+
scanner.setOnError((message, length, arg0) => {
31369+
// emulate `parseErrorAtPosition` from parser.ts
31370+
const start = scanner!.getTokenEnd();
31371+
if (message.category === DiagnosticCategory.Message && lastError && start === lastError.start && length === lastError.length) {
31372+
const error = createDetachedDiagnostic(sourceFile.fileName, sourceFile.text, start, length, message, arg0);
31373+
addRelatedInfo(lastError, error);
31374+
}
31375+
else if (!lastError || start !== lastError.start) {
31376+
lastError = createFileDiagnostic(sourceFile, start, length, message, arg0);
31377+
diagnostics.add(lastError);
31378+
}
31379+
});
31380+
scanner.setText(sourceFile.text, node.pos, node.end - node.pos);
31381+
try {
31382+
scanner.scan();
31383+
Debug.assert(scanner.reScanSlashToken(/*reportErrors*/ true) === SyntaxKind.RegularExpressionLiteral, "Expected scanner to rescan RegularExpressionLiteral");
31384+
return !!lastError;
31385+
}
31386+
finally {
31387+
scanner.setText("");
31388+
scanner.setOnError(/*onError*/ undefined);
31389+
}
31390+
}
31391+
return false;
31392+
}
31393+
31394+
function checkRegularExpressionLiteral(node: RegularExpressionLiteral) {
31395+
const nodeLinks = getNodeLinks(node);
31396+
if (!(nodeLinks.flags & NodeCheckFlags.TypeChecked)) {
31397+
nodeLinks.flags |= NodeCheckFlags.TypeChecked;
31398+
addLazyDiagnostic(() => checkGrammarRegularExpressionLiteral(node));
31399+
}
31400+
return globalRegExpType;
31401+
}
31402+
3135631403
function checkSpreadExpression(node: SpreadElement, checkMode?: CheckMode): Type {
3135731404
if (languageVersion < LanguageFeatureMinimumTarget.SpreadElements) {
3135831405
checkExternalEmitHelpers(node, compilerOptions.downlevelIteration ? ExternalEmitHelpers.SpreadIncludes : ExternalEmitHelpers.SpreadArray);
@@ -38493,7 +38540,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3849338540
parent = parent.parent;
3849438541
}
3849538542
if (operator === SyntaxKind.AmpersandAmpersandToken || isIfStatement(parent)) {
38496-
checkTestingKnownTruthyCallableOrAwaitableType(node.left, leftType, isIfStatement(parent) ? parent.thenStatement : undefined);
38543+
checkTestingKnownTruthyCallableOrAwaitableOrEnumMemberType(node.left, leftType, isIfStatement(parent) ? parent.thenStatement : undefined);
3849738544
}
3849838545
checkTruthinessOfType(leftType, node.left);
3849938546
}
@@ -39127,7 +39174,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3912739174

3912839175
function checkConditionalExpression(node: ConditionalExpression, checkMode?: CheckMode): Type {
3912939176
const type = checkTruthinessExpression(node.condition, checkMode);
39130-
checkTestingKnownTruthyCallableOrAwaitableType(node.condition, type, node.whenTrue);
39177+
checkTestingKnownTruthyCallableOrAwaitableOrEnumMemberType(node.condition, type, node.whenTrue);
3913139178
const type1 = checkExpression(node.whenTrue, checkMode);
3913239179
const type2 = checkExpression(node.whenFalse, checkMode);
3913339180
return getUnionType([type1, type2], UnionReduction.Subtype);
@@ -39662,7 +39709,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3966239709
case SyntaxKind.TemplateExpression:
3966339710
return checkTemplateExpression(node as TemplateExpression);
3966439711
case SyntaxKind.RegularExpressionLiteral:
39665-
return globalRegExpType;
39712+
return checkRegularExpressionLiteral(node as RegularExpressionLiteral);
3966639713
case SyntaxKind.ArrayLiteralExpression:
3966739714
return checkArrayLiteral(node as ArrayLiteralExpression, checkMode, forceTuple);
3966839715
case SyntaxKind.ObjectLiteralExpression:
@@ -43101,7 +43148,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4310143148
// Grammar checking
4310243149
checkGrammarStatementInAmbientContext(node);
4310343150
const type = checkTruthinessExpression(node.expression);
43104-
checkTestingKnownTruthyCallableOrAwaitableType(node.expression, type, node.thenStatement);
43151+
checkTestingKnownTruthyCallableOrAwaitableOrEnumMemberType(node.expression, type, node.thenStatement);
4310543152
checkSourceElement(node.thenStatement);
4310643153

4310743154
if (node.thenStatement.kind === SyntaxKind.EmptyStatement) {
@@ -43111,7 +43158,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4311143158
checkSourceElement(node.elseStatement);
4311243159
}
4311343160

43114-
function checkTestingKnownTruthyCallableOrAwaitableType(condExpr: Expression, condType: Type, body?: Statement | Expression) {
43161+
function checkTestingKnownTruthyCallableOrAwaitableOrEnumMemberType(condExpr: Expression, condType: Type, body?: Statement | Expression) {
4311543162
if (!strictNullChecks) return;
4311643163
bothHelper(condExpr, body);
4311743164

@@ -43136,6 +43183,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4313643183
return;
4313743184
}
4313843185
const type = location === condExpr ? condType : checkTruthinessExpression(location);
43186+
if (type.flags & TypeFlags.EnumLiteral && isPropertyAccessExpression(location) && (getNodeLinks(location.expression).resolvedSymbol ?? unknownSymbol).flags & SymbolFlags.Enum) {
43187+
// EnumLiteral type at condition with known value is always truthy or always falsy, likely an error
43188+
error(location, Diagnostics.This_condition_will_always_return_0, !!(type as LiteralType).value ? "true" : "false");
43189+
return;
43190+
}
4313943191
const isPropertyExpressionCast = isPropertyAccessExpression(location) && isTypeAssertion(location.expression);
4314043192
if (!hasTypeFacts(type, TypeFacts.Truthy) || isPropertyExpressionCast) return;
4314143193

@@ -46279,7 +46331,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4627946331
// If we hit an import declaration in an illegal context, just bail out to avoid cascading errors.
4628046332
return;
4628146333
}
46282-
if (!checkGrammarModifiers(node) && hasEffectiveModifiers(node)) {
46334+
if (!checkGrammarModifiers(node) && node.modifiers) {
4628346335
grammarErrorOnFirstToken(node, Diagnostics.An_import_declaration_cannot_have_modifiers);
4628446336
}
4628546337
if (checkExternalImportOrExportDeclaration(node)) {

src/compiler/corePublic.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
export const versionMajorMinor = "5.5";
44
// The following is baselined as a literal template type without intervention
55
/** The version of the TypeScript compiler release */
6-
// eslint-disable-next-line @typescript-eslint/no-inferrable-types
76
export const version: string = `${versionMajorMinor}.0-dev`;
87

98
/**

src/compiler/diagnosticMessages.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,11 +1785,11 @@
17851785
"category": "Error",
17861786
"code": 1532
17871787
},
1788-
"A decimal escape must refer to an existent capturing group. There are only {0} capturing groups in this regular expression.": {
1788+
"This backreference refers to a group that does not exist. There are only {0} capturing groups in this regular expression.": {
17891789
"category": "Error",
17901790
"code": 1533
17911791
},
1792-
"Decimal escapes are invalid when there are no capturing groups in a regular expression.": {
1792+
"This backreference is invalid because the containing regular expression contains no capturing groups.": {
17931793
"category": "Error",
17941794
"code": 1534
17951795
},

src/compiler/emitter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ function getSourceMapFilePath(jsFilePath: string, options: CompilerOptions) {
533533
}
534534

535535
/** @internal */
536-
export function getOutputExtension(fileName: string, options: CompilerOptions): Extension {
536+
export function getOutputExtension(fileName: string, options: Pick<CompilerOptions, "jsx">): Extension {
537537
return fileExtensionIs(fileName, Extension.Json) ? Extension.Json :
538538
options.jsx === JsxEmit.Preserve && fileExtensionIsOneOf(fileName, [Extension.Jsx, Extension.Tsx]) ? Extension.Jsx :
539539
fileExtensionIsOneOf(fileName, [Extension.Mts, Extension.Mjs]) ? Extension.Mjs :

0 commit comments

Comments
 (0)