Skip to content

Commit e72ca86

Browse files
committed
Merge branch 'master' into delete-legacy-empty-obj-type-param-rule
2 parents 41423f0 + 931e33f commit e72ca86

File tree

54 files changed

+889
-101
lines changed

Some content is hidden

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

54 files changed

+889
-101
lines changed

src/compiler/checker.ts

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18532,6 +18532,32 @@ namespace ts {
1853218532
}
1853318533
// Infer from the members of source and target only if the two types are possibly related
1853418534
if (!typesDefinitelyUnrelated(source, target)) {
18535+
if (isArrayType(source) || isTupleType(source)) {
18536+
if (isTupleType(target)) {
18537+
const sourceLength = isTupleType(source) ? getLengthOfTupleType(source) : 0;
18538+
const targetLength = getLengthOfTupleType(target);
18539+
const sourceRestType = isTupleType(source) ? getRestTypeOfTupleType(source) : getElementTypeOfArrayType(source);
18540+
const targetRestType = getRestTypeOfTupleType(target);
18541+
const fixedLength = targetLength < sourceLength || sourceRestType ? targetLength : sourceLength;
18542+
for (let i = 0; i < fixedLength; i++) {
18543+
inferFromTypes(i < sourceLength ? getTypeArguments(<TypeReference>source)[i] : sourceRestType!, getTypeArguments(target)[i]);
18544+
}
18545+
if (targetRestType) {
18546+
const types = fixedLength < sourceLength ? getTypeArguments(<TypeReference>source).slice(fixedLength, sourceLength) : [];
18547+
if (sourceRestType) {
18548+
types.push(sourceRestType);
18549+
}
18550+
if (types.length) {
18551+
inferFromTypes(getUnionType(types), targetRestType);
18552+
}
18553+
}
18554+
return;
18555+
}
18556+
if (isArrayType(target)) {
18557+
inferFromIndexTypes(source, target);
18558+
return;
18559+
}
18560+
}
1853518561
inferFromProperties(source, target);
1853618562
inferFromSignatures(source, target, SignatureKind.Call);
1853718563
inferFromSignatures(source, target, SignatureKind.Construct);
@@ -18540,32 +18566,6 @@ namespace ts {
1854018566
}
1854118567

1854218568
function inferFromProperties(source: Type, target: Type) {
18543-
if (isArrayType(source) || isTupleType(source)) {
18544-
if (isTupleType(target)) {
18545-
const sourceLength = isTupleType(source) ? getLengthOfTupleType(source) : 0;
18546-
const targetLength = getLengthOfTupleType(target);
18547-
const sourceRestType = isTupleType(source) ? getRestTypeOfTupleType(source) : getElementTypeOfArrayType(source);
18548-
const targetRestType = getRestTypeOfTupleType(target);
18549-
const fixedLength = targetLength < sourceLength || sourceRestType ? targetLength : sourceLength;
18550-
for (let i = 0; i < fixedLength; i++) {
18551-
inferFromTypes(i < sourceLength ? getTypeArguments(<TypeReference>source)[i] : sourceRestType!, getTypeArguments(target)[i]);
18552-
}
18553-
if (targetRestType) {
18554-
const types = fixedLength < sourceLength ? getTypeArguments(<TypeReference>source).slice(fixedLength, sourceLength) : [];
18555-
if (sourceRestType) {
18556-
types.push(sourceRestType);
18557-
}
18558-
if (types.length) {
18559-
inferFromTypes(getUnionType(types), targetRestType);
18560-
}
18561-
}
18562-
return;
18563-
}
18564-
if (isArrayType(target)) {
18565-
inferFromIndexTypes(source, target);
18566-
return;
18567-
}
18568-
}
1856918569
const properties = getPropertiesOfObjectType(target);
1857018570
for (const targetProp of properties) {
1857118571
const sourceProp = getPropertyOfType(source, targetProp.escapedName);

src/compiler/commandLineParser.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ namespace ts {
5757
["esnext.symbol", "lib.es2019.symbol.d.ts"],
5858
["esnext.asynciterable", "lib.es2018.asynciterable.d.ts"],
5959
["esnext.intl", "lib.esnext.intl.d.ts"],
60-
["esnext.bigint", "lib.es2020.bigint.d.ts"]
60+
["esnext.bigint", "lib.es2020.bigint.d.ts"],
61+
["esnext.string", "lib.esnext.string.d.ts"]
6162
];
6263

6364
/**

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2245,6 +2245,10 @@
22452245
"category": "Error",
22462246
"code": 2577
22472247
},
2248+
"Unused '@ts-expect-error' directive.": {
2249+
"category": "Error",
2250+
"code": 2578
2251+
},
22482252
"Cannot find name '{0}'. Do you need to install type definitions for node? Try `npm i @types/node`.": {
22492253
"category": "Error",
22502254
"code": 2580

src/compiler/emitter.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2273,7 +2273,7 @@ namespace ts {
22732273

22742274
function emitPropertyAccessExpression(node: PropertyAccessExpression) {
22752275
const expression = cast(emitExpression(node.expression), isExpression);
2276-
const token = getDotOrQuestionDotToken(node);
2276+
const token = node.questionDotToken || createNode(SyntaxKind.DotToken, node.expression.end, node.name.pos) as DotToken;
22772277
const indentBeforeDot = needsIndentation(node, node.expression, token);
22782278
const indentAfterDot = needsIndentation(node, token, node.name);
22792279

@@ -2289,7 +2289,12 @@ namespace ts {
22892289
writePunctuation(".");
22902290
}
22912291

2292-
emitTokenWithComment(token.kind, node.expression.end, writePunctuation, node);
2292+
if (node.questionDotToken) {
2293+
emit(token);
2294+
}
2295+
else {
2296+
emitTokenWithComment(token.kind, node.expression.end, writePunctuation, node);
2297+
}
22932298
increaseIndentIf(indentAfterDot, /*writeSpaceIfNotIndenting*/ false);
22942299
emit(node.name);
22952300
decreaseIndentIf(indentBeforeDot, indentAfterDot);

src/compiler/parser.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,7 @@ namespace ts {
915915

916916
function clearState() {
917917
// Clear out the text the scanner is pointing at, so it doesn't keep anything alive unnecessarily.
918+
scanner.clearCommentDirectives();
918919
scanner.setText("");
919920
scanner.setOnError(undefined);
920921

@@ -948,6 +949,7 @@ namespace ts {
948949

949950
setExternalModuleIndicator(sourceFile);
950951

952+
sourceFile.commentDirectives = scanner.getCommentDirectives();
951953
sourceFile.nodeCount = nodeCount;
952954
sourceFile.identifierCount = identifierCount;
953955
sourceFile.identifiers = identifiers;

src/compiler/program.ts

Lines changed: 61 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
namespace ts {
2-
const ignoreDiagnosticCommentRegEx = /(^\s*$)|(^\s*\/\/\/?\s*(@ts-ignore)?)/;
3-
42
export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName = "tsconfig.json"): string | undefined {
53
return forEachAncestorDirectory(searchPath, ancestor => {
64
const fileName = combinePaths(ancestor, configName);
@@ -1661,17 +1659,16 @@ namespace ts {
16611659
const fileProcessingDiagnosticsInFile = fileProcessingDiagnostics.getDiagnostics(sourceFile.fileName);
16621660
const programDiagnosticsInFile = programDiagnostics.getDiagnostics(sourceFile.fileName);
16631661

1664-
let diagnostics: Diagnostic[] | undefined;
1665-
for (const diags of [fileProcessingDiagnosticsInFile, programDiagnosticsInFile]) {
1666-
if (diags) {
1667-
for (const diag of diags) {
1668-
if (shouldReportDiagnostic(diag)) {
1669-
diagnostics = append(diagnostics, diag);
1670-
}
1671-
}
1672-
}
1662+
return getMergedProgramDiagnostics(sourceFile, fileProcessingDiagnosticsInFile, programDiagnosticsInFile);
1663+
}
1664+
1665+
function getMergedProgramDiagnostics(sourceFile: SourceFile, ...allDiagnostics: (readonly Diagnostic[] | undefined)[]) {
1666+
const flatDiagnostics = flatten(allDiagnostics);
1667+
if (!sourceFile.commentDirectives?.length) {
1668+
return flatDiagnostics;
16731669
}
1674-
return diagnostics || emptyArray;
1670+
1671+
return getDiagnosticsWithPrecedingDirectives(sourceFile, sourceFile.commentDirectives, flatDiagnostics).diagnostics;
16751672
}
16761673

16771674
function getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[] {
@@ -1749,49 +1746,72 @@ namespace ts {
17491746
const bindDiagnostics: readonly Diagnostic[] = includeBindAndCheckDiagnostics ? sourceFile.bindDiagnostics : emptyArray;
17501747
const checkDiagnostics = includeBindAndCheckDiagnostics ? typeChecker.getDiagnostics(sourceFile, cancellationToken) : emptyArray;
17511748

1752-
let diagnostics: Diagnostic[] | undefined;
1753-
for (const diags of [bindDiagnostics, checkDiagnostics, isCheckJs ? sourceFile.jsDocDiagnostics : undefined]) {
1754-
if (diags) {
1755-
for (const diag of diags) {
1756-
if (shouldReportDiagnostic(diag)) {
1757-
diagnostics = append(diagnostics, diag);
1758-
}
1759-
}
1760-
}
1761-
}
1762-
return diagnostics || emptyArray;
1749+
return getMergedBindAndCheckDiagnostics(sourceFile, bindDiagnostics, checkDiagnostics, isCheckJs ? sourceFile.jsDocDiagnostics : undefined);
17631750
});
17641751
}
17651752

1753+
function getMergedBindAndCheckDiagnostics(sourceFile: SourceFile, ...allDiagnostics: (readonly Diagnostic[] | undefined)[]) {
1754+
const flatDiagnostics = flatten(allDiagnostics);
1755+
if (!sourceFile.commentDirectives?.length) {
1756+
return flatDiagnostics;
1757+
}
1758+
1759+
const { diagnostics, directives } = getDiagnosticsWithPrecedingDirectives(sourceFile, sourceFile.commentDirectives, flatDiagnostics);
1760+
1761+
for (const errorExpectation of directives.getUnusedExpectations()) {
1762+
diagnostics.push(createDiagnosticForRange(sourceFile, errorExpectation.range, Diagnostics.Unused_ts_expect_error_directive));
1763+
}
1764+
1765+
return diagnostics;
1766+
}
1767+
1768+
/**
1769+
* Creates a map of comment directives along with the diagnostics immediately preceded by one of them.
1770+
* Comments that match to any of those diagnostics are marked as used.
1771+
*/
1772+
function getDiagnosticsWithPrecedingDirectives(sourceFile: SourceFile, commentDirectives: CommentDirective[], flatDiagnostics: Diagnostic[]) {
1773+
// Diagnostics are only reported if there is no comment directive preceding them
1774+
// This will modify the directives map by marking "used" ones with a corresponding diagnostic
1775+
const directives = createCommentDirectivesMap(sourceFile, commentDirectives);
1776+
const diagnostics = flatDiagnostics.filter(diagnostic => markPrecedingCommentDirectiveLine(diagnostic, directives) === -1);
1777+
1778+
return { diagnostics, directives };
1779+
}
1780+
17661781
function getSuggestionDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): readonly DiagnosticWithLocation[] {
17671782
return runWithCancellationToken(() => {
17681783
return getDiagnosticsProducingTypeChecker().getSuggestionDiagnostics(sourceFile, cancellationToken);
17691784
});
17701785
}
17711786

17721787
/**
1773-
* Skip errors if previous line start with '// @ts-ignore' comment, not counting non-empty non-comment lines
1788+
* @returns The line index marked as preceding the diagnostic, or -1 if none was.
17741789
*/
1775-
function shouldReportDiagnostic(diagnostic: Diagnostic) {
1790+
function markPrecedingCommentDirectiveLine(diagnostic: Diagnostic, directives: CommentDirectivesMap) {
17761791
const { file, start } = diagnostic;
1777-
if (file) {
1778-
const lineStarts = getLineStarts(file);
1779-
let { line } = computeLineAndCharacterOfPosition(lineStarts, start!); // TODO: GH#18217
1780-
while (line > 0) {
1781-
const previousLineText = file.text.slice(lineStarts[line - 1], lineStarts[line]);
1782-
const result = ignoreDiagnosticCommentRegEx.exec(previousLineText);
1783-
if (!result) {
1784-
// non-empty line
1785-
return true;
1786-
}
1787-
if (result[3]) {
1788-
// @ts-ignore
1789-
return false;
1790-
}
1791-
line--;
1792+
if (!file) {
1793+
return -1;
1794+
}
1795+
1796+
// Start out with the line just before the text
1797+
const lineStarts = getLineStarts(file);
1798+
let line = computeLineAndCharacterOfPosition(lineStarts, start!).line - 1; // TODO: GH#18217
1799+
while (line >= 0) {
1800+
// As soon as that line is known to have a comment directive, use that
1801+
if (directives.markUsed(line)) {
1802+
return line;
17921803
}
1804+
1805+
// Stop searching if the line is not empty and not a comment
1806+
const lineText = file.text.slice(lineStarts[line - 1], lineStarts[line]).trim();
1807+
if (lineText !== "" && !/^(\s*)\/\/(.*)$/.test(lineText)) {
1808+
return -1;
1809+
}
1810+
1811+
line--;
17931812
}
1794-
return true;
1813+
1814+
return -1;
17951815
}
17961816

17971817
function getJSSyntacticDiagnosticsForFile(sourceFile: SourceFile): DiagnosticWithLocation[] {

0 commit comments

Comments
 (0)