Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into release-5.5
Browse files Browse the repository at this point in the history
  • Loading branch information
typescript-bot committed Apr 25, 2024
2 parents ecf3789 + 9504b75 commit 593f200
Show file tree
Hide file tree
Showing 41 changed files with 1,448 additions and 814 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
- windows-latest
- macos-14
node-version:
- '22'
- '20'
- '18'
- '16'
Expand Down
66 changes: 59 additions & 7 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ import {
countWhere,
createBinaryExpressionTrampoline,
createCompilerDiagnostic,
createDetachedDiagnostic,
createDiagnosticCollection,
createDiagnosticForFileFromMessageChain,
createDiagnosticForNode,
Expand All @@ -123,6 +124,7 @@ import {
createPrinterWithRemoveCommentsNeverAsciiEscape,
createPrinterWithRemoveCommentsOmitTrailingSemicolon,
createPropertyNameNodeForIdentifierOrLiteral,
createScanner,
createSymbolTable,
createSyntacticTypeNodeBuilder,
createTextWriter,
Expand Down Expand Up @@ -937,6 +939,7 @@ import {
rangeOfTypeParameters,
ReadonlyKeyword,
reduceLeft,
RegularExpressionLiteral,
RelationComparisonResult,
relativeComplement,
removeExtension,
Expand All @@ -953,6 +956,7 @@ import {
ReverseMappedType,
sameMap,
SatisfiesExpression,
Scanner,
scanTokenAtPosition,
ScriptKind,
ScriptTarget,
Expand Down Expand Up @@ -1446,6 +1450,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
var requestedExternalEmitHelperNames = new Set<string>();
var requestedExternalEmitHelpers: ExternalEmitHelpers;
var externalHelpersModule: Symbol;
var scanner: Scanner | undefined;

var Symbol = objectAllocator.getSymbolConstructor();
var Type = objectAllocator.getTypeConstructor();
Expand Down Expand Up @@ -6689,7 +6694,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (!nodeIsSynthesized(node) && getParseTreeNode(node) === node) {
return node;
}
return setTextRange(context, factory.cloneNode(visitEachChild(node, deepCloneOrReuseNode, /*context*/ undefined, deepCloneOrReuseNodes)), node);
return setTextRange(context, factory.cloneNode(visitEachChild(node, deepCloneOrReuseNode, /*context*/ undefined, deepCloneOrReuseNodes, deepCloneOrReuseNode)), node);
}

function deepCloneOrReuseNodes(
Expand Down Expand Up @@ -31353,6 +31358,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}

function checkGrammarRegularExpressionLiteral(node: RegularExpressionLiteral) {
const sourceFile = getSourceFileOfNode(node);
if (!hasParseDiagnostics(sourceFile)) {
let lastError: DiagnosticWithLocation | undefined;
scanner ??= createScanner(ScriptTarget.ESNext, /*skipTrivia*/ true);
scanner.setScriptTarget(sourceFile.languageVersion);
scanner.setLanguageVariant(sourceFile.languageVariant);
scanner.setOnError((message, length, arg0) => {
// emulate `parseErrorAtPosition` from parser.ts
const start = scanner!.getTokenEnd();
if (message.category === DiagnosticCategory.Message && lastError && start === lastError.start && length === lastError.length) {
const error = createDetachedDiagnostic(sourceFile.fileName, sourceFile.text, start, length, message, arg0);
addRelatedInfo(lastError, error);
}
else if (!lastError || start !== lastError.start) {
lastError = createFileDiagnostic(sourceFile, start, length, message, arg0);
diagnostics.add(lastError);
}
});
scanner.setText(sourceFile.text, node.pos, node.end - node.pos);
try {
scanner.scan();
Debug.assert(scanner.reScanSlashToken(/*reportErrors*/ true) === SyntaxKind.RegularExpressionLiteral, "Expected scanner to rescan RegularExpressionLiteral");
return !!lastError;
}
finally {
scanner.setText("");
scanner.setOnError(/*onError*/ undefined);
}
}
return false;
}

function checkRegularExpressionLiteral(node: RegularExpressionLiteral) {
const nodeLinks = getNodeLinks(node);
if (!(nodeLinks.flags & NodeCheckFlags.TypeChecked)) {
nodeLinks.flags |= NodeCheckFlags.TypeChecked;
addLazyDiagnostic(() => checkGrammarRegularExpressionLiteral(node));
}
return globalRegExpType;
}

function checkSpreadExpression(node: SpreadElement, checkMode?: CheckMode): Type {
if (languageVersion < LanguageFeatureMinimumTarget.SpreadElements) {
checkExternalEmitHelpers(node, compilerOptions.downlevelIteration ? ExternalEmitHelpers.SpreadIncludes : ExternalEmitHelpers.SpreadArray);
Expand Down Expand Up @@ -38493,7 +38540,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
parent = parent.parent;
}
if (operator === SyntaxKind.AmpersandAmpersandToken || isIfStatement(parent)) {
checkTestingKnownTruthyCallableOrAwaitableType(node.left, leftType, isIfStatement(parent) ? parent.thenStatement : undefined);
checkTestingKnownTruthyCallableOrAwaitableOrEnumMemberType(node.left, leftType, isIfStatement(parent) ? parent.thenStatement : undefined);
}
checkTruthinessOfType(leftType, node.left);
}
Expand Down Expand Up @@ -39127,7 +39174,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {

function checkConditionalExpression(node: ConditionalExpression, checkMode?: CheckMode): Type {
const type = checkTruthinessExpression(node.condition, checkMode);
checkTestingKnownTruthyCallableOrAwaitableType(node.condition, type, node.whenTrue);
checkTestingKnownTruthyCallableOrAwaitableOrEnumMemberType(node.condition, type, node.whenTrue);
const type1 = checkExpression(node.whenTrue, checkMode);
const type2 = checkExpression(node.whenFalse, checkMode);
return getUnionType([type1, type2], UnionReduction.Subtype);
Expand Down Expand Up @@ -39662,7 +39709,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
case SyntaxKind.TemplateExpression:
return checkTemplateExpression(node as TemplateExpression);
case SyntaxKind.RegularExpressionLiteral:
return globalRegExpType;
return checkRegularExpressionLiteral(node as RegularExpressionLiteral);
case SyntaxKind.ArrayLiteralExpression:
return checkArrayLiteral(node as ArrayLiteralExpression, checkMode, forceTuple);
case SyntaxKind.ObjectLiteralExpression:
Expand Down Expand Up @@ -43101,7 +43148,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// Grammar checking
checkGrammarStatementInAmbientContext(node);
const type = checkTruthinessExpression(node.expression);
checkTestingKnownTruthyCallableOrAwaitableType(node.expression, type, node.thenStatement);
checkTestingKnownTruthyCallableOrAwaitableOrEnumMemberType(node.expression, type, node.thenStatement);
checkSourceElement(node.thenStatement);

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

function checkTestingKnownTruthyCallableOrAwaitableType(condExpr: Expression, condType: Type, body?: Statement | Expression) {
function checkTestingKnownTruthyCallableOrAwaitableOrEnumMemberType(condExpr: Expression, condType: Type, body?: Statement | Expression) {
if (!strictNullChecks) return;
bothHelper(condExpr, body);

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

Expand Down Expand Up @@ -46279,7 +46331,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// If we hit an import declaration in an illegal context, just bail out to avoid cascading errors.
return;
}
if (!checkGrammarModifiers(node) && hasEffectiveModifiers(node)) {
if (!checkGrammarModifiers(node) && node.modifiers) {
grammarErrorOnFirstToken(node, Diagnostics.An_import_declaration_cannot_have_modifiers);
}
if (checkExternalImportOrExportDeclaration(node)) {
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1785,11 +1785,11 @@
"category": "Error",
"code": 1532
},
"A decimal escape must refer to an existent capturing group. There are only {0} capturing groups in this regular expression.": {
"This backreference refers to a group that does not exist. There are only {0} capturing groups in this regular expression.": {
"category": "Error",
"code": 1533
},
"Decimal escapes are invalid when there are no capturing groups in a regular expression.": {
"This backreference is invalid because the containing regular expression contains no capturing groups.": {
"category": "Error",
"code": 1534
},
Expand Down
Loading

0 comments on commit 593f200

Please sign in to comment.