Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report multiple overload errors #32092

Merged
merged 35 commits into from
Jul 8, 2019
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c65d9f2
Initial attempt. Totally doesn't work.
sandersn Jun 18, 2019
beddf9c
Working, just not the way I would like
sandersn Jun 18, 2019
caff266
Notes on how to return errors from checkTypeRelatedTo
sandersn Jun 18, 2019
e5fd876
Merge branch 'master' into report-multiple-overload-errors
sandersn Jun 19, 2019
1f6ef05
Re-add multiple errors
sandersn Jun 19, 2019
afecb87
Use related spans to form a tree of errors.
sandersn Jun 20, 2019
ef0a875
Share code a bit better
sandersn Jun 20, 2019
b85796c
Retain related info for 1-overloads
sandersn Jun 20, 2019
720ad5b
Improve error message and update baselines
sandersn Jun 21, 2019
ecfa902
Use existing reporting mechanism
sandersn Jun 24, 2019
f20f700
Update baselines, except JSX
sandersn Jun 25, 2019
66244f7
Don't double-check JSX calls
sandersn Jun 25, 2019
67b8ca7
Merge branch 'master' into report-multiple-overload-errors
sandersn Jun 25, 2019
b58932e
Fix lint and remove done TODOs
sandersn Jun 25, 2019
68968fd
Improve error messages and related spans
sandersn Jun 26, 2019
c0ff286
Merge branch 'master' into report-multiple-overload-errors
sandersn Jun 26, 2019
0436cfc
Do not report multiple diagnostics per signature.
sandersn Jun 26, 2019
35dda10
Fix lint, remove overloads
sandersn Jun 27, 2019
ba9d8e2
Switch DiagnosticMessageChain to be a tree
sandersn Jun 27, 2019
47bbc95
Convert related spans to message chains
sandersn Jun 28, 2019
c48018f
Merge branch 'master' into report-multiple-overload-errors
sandersn Jun 28, 2019
9778474
Fix lint
sandersn Jun 28, 2019
71276a2
Merge branch 'master' into report-multiple-overload-errors
sandersn Jun 28, 2019
34c4047
Update baselines with new error numbers
sandersn Jun 28, 2019
cce2b93
Merge branch 'master' into report-multiple-overload-errors
sandersn Jul 1, 2019
1906142
Update baselines
sandersn Jul 1, 2019
f139455
Address PR comments
sandersn Jul 1, 2019
de52797
Update baselines
sandersn Jul 2, 2019
e62d84c
Merge branch 'master' into report-multiple-overload-errors
sandersn Jul 3, 2019
d92e8ea
Update baselines
sandersn Jul 3, 2019
722917f
Remove TODO
sandersn Jul 3, 2019
19b593e
Merge branch 'master' into report-multiple-overload-errors
sandersn Jul 3, 2019
834a476
Merge branch 'master' into report-multiple-overload-errors
sandersn Jul 8, 2019
2233eba
Update baselines
sandersn Jul 8, 2019
05a4e8f
Update more baselines (?)
sandersn Jul 8, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
299 changes: 224 additions & 75 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

24 changes: 9 additions & 15 deletions src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -600,24 +600,18 @@ namespace ts {
*
* @param array The array to flatten.
*/
export function flatten<T>(array: ReadonlyArray<T | ReadonlyArray<T> | undefined>): T[];
export function flatten<T>(array: ReadonlyArray<T | ReadonlyArray<T> | undefined> | undefined): T[] | undefined;
export function flatten<T>(array: ReadonlyArray<T | ReadonlyArray<T> | undefined> | undefined): T[] | undefined {
let result: T[] | undefined;
if (array) {
result = [];
for (const v of array) {
if (v) {
if (isArray(v)) {
addRange(result, v);
}
else {
result.push(v);
}
export function flatten<T>(array: T[][] | ReadonlyArray<T | ReadonlyArray<T> | undefined>): T[] {
const result = [];
for (const v of array) {
if (v) {
if (isArray(v)) {
addRange(result, v);
}
else {
result.push(v);
}
}
}

return result;
}

Expand Down
16 changes: 16 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -2677,6 +2677,22 @@
"category": "Error",
"code": 2768
},
"No overload matches this call.": {
"category": "Error",
"code": 2769
},
"The last overload gave the following error.": {
"category": "Error",
"code": 2770
},
"The last overload is declared here.": {
"category": "Error",
"code": 2771
},
"Overload {0} of {1}, '{2}', gave the following error.": {
"category": "Error",
"code": 2772
},

"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
Expand Down
39 changes: 19 additions & 20 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -502,30 +502,29 @@ namespace ts {
return output;
}

export function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain | undefined, newLine: string): string {
if (isString(messageText)) {
return messageText;
export function flattenDiagnosticMessageText(diag: string | DiagnosticMessageChain | undefined, newLine: string, indent = 0): string {
if (isString(diag)) {
return diag;
}
else {
let diagnosticChain = messageText;
let result = "";

let indent = 0;
while (diagnosticChain) {
if (indent) {
result += newLine;
else if (diag === undefined) {
return "";
}
let result = "";
if (indent) {
result += newLine;

for (let i = 0; i < indent; i++) {
result += " ";
}
}
result += diagnosticChain.messageText;
indent++;
diagnosticChain = diagnosticChain.next;
for (let i = 0; i < indent; i++) {
result += " ";
}
}
result += diag.messageText;
indent++;
if (diag.next) {
for (const kid of diag.next) {
result += flattenDiagnosticMessageText(kid, newLine, indent);
}

return result;
}
return result;
}

/* @internal */
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4577,7 +4577,7 @@ namespace ts {
messageText: string;
category: DiagnosticCategory;
code: number;
next?: DiagnosticMessageChain;
next?: DiagnosticMessageChain[];
}

export interface Diagnostic extends DiagnosticRelatedInformation {
Expand Down
64 changes: 38 additions & 26 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7125,8 +7125,8 @@ namespace ts {
};
}

export function chainDiagnosticMessages(details: DiagnosticMessageChain | undefined, message: DiagnosticMessage, ...args: (string | number | undefined)[]): DiagnosticMessageChain;
export function chainDiagnosticMessages(details: DiagnosticMessageChain | undefined, message: DiagnosticMessage): DiagnosticMessageChain {
export function chainDiagnosticMessages(details: DiagnosticMessageChain | DiagnosticMessageChain[] | undefined, message: DiagnosticMessage, ...args: (string | number | undefined)[]): DiagnosticMessageChain;
export function chainDiagnosticMessages(details: DiagnosticMessageChain | DiagnosticMessageChain[] | undefined, message: DiagnosticMessage): DiagnosticMessageChain {
let text = getLocaleSpecificMessage(message);

if (arguments.length > 2) {
Expand All @@ -7138,18 +7138,17 @@ namespace ts {
category: message.category,
code: message.code,

next: details
next: details === undefined || Array.isArray(details) ? details : [details]
};
}

export function concatenateDiagnosticMessageChains(headChain: DiagnosticMessageChain, tailChain: DiagnosticMessageChain): DiagnosticMessageChain {
export function concatenateDiagnosticMessageChains(headChain: DiagnosticMessageChain, tailChain: DiagnosticMessageChain): void {
let lastChain = headChain;
while (lastChain.next) {
lastChain = lastChain.next;
lastChain = lastChain.next[0];
}

lastChain.next = tailChain;
return headChain;
lastChain.next = [tailChain];
}

function getDiagnosticFilePath(diagnostic: Diagnostic): string | undefined {
Expand Down Expand Up @@ -7185,29 +7184,42 @@ namespace ts {
}

function compareMessageText(t1: string | DiagnosticMessageChain, t2: string | DiagnosticMessageChain): Comparison {
let text1: string | DiagnosticMessageChain | undefined = t1;
let text2: string | DiagnosticMessageChain | undefined = t2;
while (text1 && text2) {
// We still have both chains.
const string1 = isString(text1) ? text1 : text1.messageText;
const string2 = isString(text2) ? text2 : text2.messageText;

const res = compareStringsCaseSensitive(string1, string2);
if (typeof t1 === "string" && typeof t2 === "string") {
return compareStringsCaseSensitive(t1, t2);
}
else if (typeof t1 === "string") {
return Comparison.LessThan;
}
else if (typeof t2 === "string") {
return Comparison.GreaterThan;
}
let res = compareStringsCaseSensitive(t1.messageText, t2.messageText);
if (res) {
return res;
}
if (!t1.next && !t2.next) {
return Comparison.EqualTo;
}
if (!t1.next) {
return Comparison.LessThan;
}
if (!t2.next) {
return Comparison.GreaterThan;
}
const len = Math.min(t1.next.length, t2.next.length);
for (let i = 0; i < len; i++) {
res = compareMessageText(t1.next[i], t2.next[i]);
if (res) {
return res;
}

text1 = isString(text1) ? undefined : text1.next;
text2 = isString(text2) ? undefined : text2.next;
}

if (!text1 && !text2) {
// if the chains are done, then these messages are the same.
return Comparison.EqualTo;
if (t1.next.length < t2.next.length) {
return Comparison.LessThan;
}

// We still have one chain remaining. The shorter chain should come first.
return text1 ? Comparison.GreaterThan : Comparison.LessThan;
else if (t1.next.length > t2.next.length) {
return Comparison.GreaterThan;
}
return Comparison.EqualTo;
}

export function getEmitScriptTarget(compilerOptions: CompilerOptions) {
Expand Down Expand Up @@ -8105,7 +8117,7 @@ namespace ts {
visitDirectory(basePath, combinePaths(currentDirectory, basePath), depth);
}

return flatten<string>(results);
return flatten(results);

function visitDirectory(path: string, absolutePath: string, depth: number | undefined) {
const canonicalPath = toCanonical(realpath(absolutePath));
Expand Down
19 changes: 12 additions & 7 deletions src/harness/fourslash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1497,13 +1497,7 @@ Actual: ${stringify(fullActual)}`);
const diagnostics = ts.getPreEmitDiagnostics(this.languageService.getProgram()!); // TODO: GH#18217
for (const diagnostic of diagnostics) {
if (!ts.isString(diagnostic.messageText)) {
let chainedMessage: ts.DiagnosticMessageChain | undefined = diagnostic.messageText;
let indentation = " ";
while (chainedMessage) {
resultString += indentation + chainedMessage.messageText + Harness.IO.newLine();
chainedMessage = chainedMessage.next;
indentation = indentation + " ";
}
resultString += this.flattenChainedMessage(diagnostic.messageText);
}
else {
resultString += " " + diagnostic.messageText + Harness.IO.newLine();
Expand All @@ -1521,6 +1515,17 @@ Actual: ${stringify(fullActual)}`);
Harness.Baseline.runBaseline(ts.Debug.assertDefined(this.testData.globalOptions[MetadataOptionNames.baselineFile]), resultString);
}

private flattenChainedMessage(diag: ts.DiagnosticMessageChain, indent = " ") {
let result = "";
result += indent + diag.messageText + Harness.IO.newLine();
if (diag.next) {
for (const kid of diag.next) {
result += this.flattenChainedMessage(kid, indent + " ");
}
}
return result;
}

public baselineQuickInfo() {
const baselineFile = this.getBaselineFileName();
Harness.Baseline.runBaseline(
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2457,7 +2457,7 @@ declare namespace ts {
messageText: string;
category: DiagnosticCategory;
code: number;
next?: DiagnosticMessageChain;
next?: DiagnosticMessageChain[];
}
interface Diagnostic extends DiagnosticRelatedInformation {
/** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */
Expand Down Expand Up @@ -4277,7 +4277,7 @@ declare namespace ts {
function formatDiagnostics(diagnostics: ReadonlyArray<Diagnostic>, host: FormatDiagnosticsHost): string;
function formatDiagnostic(diagnostic: Diagnostic, host: FormatDiagnosticsHost): string;
function formatDiagnosticsWithColorAndContext(diagnostics: ReadonlyArray<Diagnostic>, host: FormatDiagnosticsHost): string;
function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain | undefined, newLine: string): string;
function flattenDiagnosticMessageText(diag: string | DiagnosticMessageChain | undefined, newLine: string, indent?: number): string;
function getConfigFileParsingDiagnostics(configFileParseResult: ParsedCommandLine): ReadonlyArray<Diagnostic>;
/**
* Create a new 'Program' instance. A Program is an immutable collection of 'SourceFile's and a 'CompilerOptions'
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2457,7 +2457,7 @@ declare namespace ts {
messageText: string;
category: DiagnosticCategory;
code: number;
next?: DiagnosticMessageChain;
next?: DiagnosticMessageChain[];
}
interface Diagnostic extends DiagnosticRelatedInformation {
/** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */
Expand Down Expand Up @@ -4277,7 +4277,7 @@ declare namespace ts {
function formatDiagnostics(diagnostics: ReadonlyArray<Diagnostic>, host: FormatDiagnosticsHost): string;
function formatDiagnostic(diagnostic: Diagnostic, host: FormatDiagnosticsHost): string;
function formatDiagnosticsWithColorAndContext(diagnostics: ReadonlyArray<Diagnostic>, host: FormatDiagnosticsHost): string;
function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain | undefined, newLine: string): string;
function flattenDiagnosticMessageText(diag: string | DiagnosticMessageChain | undefined, newLine: string, indent?: number): string;
function getConfigFileParsingDiagnostics(configFileParseResult: ParsedCommandLine): ReadonlyArray<Diagnostic>;
/**
* Create a new 'Program' instance. A Program is an immutable collection of 'SourceFile's and a 'CompilerOptions'
Expand Down
Loading