Skip to content

Commit ba9d8e2

Browse files
committed
Switch DiagnosticMessageChain to be a tree
1 parent 35dda10 commit ba9d8e2

File tree

6 files changed

+104
-79
lines changed

6 files changed

+104
-79
lines changed

src/compiler/builder.ts

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace ts {
2020
messageText: string;
2121
category: DiagnosticCategory;
2222
code: number;
23-
next?: ReusableDiagnosticMessageChain;
23+
next?: ReusableDiagnosticMessageChain[];
2424
}
2525

2626
export interface ReusableBuilderProgramState extends ReusableBuilderState {
@@ -263,20 +263,10 @@ namespace ts {
263263
}
264264

265265
function convertToDiagnosticRelatedInformation(diagnostic: ReusableDiagnosticRelatedInformation, newProgram: Program): DiagnosticRelatedInformation {
266-
const { file, messageText } = diagnostic;
266+
const { file } = diagnostic;
267267
return {
268268
...diagnostic,
269269
file: file && newProgram.getSourceFileByPath(file),
270-
messageText: messageText === undefined || isString(messageText) ?
271-
messageText :
272-
convertToDiagnosticMessageChain(messageText, newProgram)
273-
};
274-
}
275-
276-
function convertToDiagnosticMessageChain(diagnostic: ReusableDiagnosticMessageChain, newProgram: Program): DiagnosticMessageChain {
277-
return {
278-
...diagnostic,
279-
next: diagnostic.next && convertToDiagnosticMessageChain(diagnostic.next, newProgram)
280270
};
281271
}
282272

@@ -685,20 +675,10 @@ namespace ts {
685675
}
686676

687677
function convertToReusableDiagnosticRelatedInformation(diagnostic: DiagnosticRelatedInformation): ReusableDiagnosticRelatedInformation {
688-
const { file, messageText } = diagnostic;
678+
const { file } = diagnostic;
689679
return {
690680
...diagnostic,
691681
file: file && file.path,
692-
messageText: messageText === undefined || isString(messageText) ?
693-
messageText :
694-
convertToReusableDiagnosticMessageChain(messageText)
695-
};
696-
}
697-
698-
function convertToReusableDiagnosticMessageChain(diagnostic: DiagnosticMessageChain): ReusableDiagnosticMessageChain {
699-
return {
700-
...diagnostic,
701-
next: diagnostic.next && convertToReusableDiagnosticMessageChain(diagnostic.next)
702682
};
703683
}
704684

src/compiler/checker.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12460,7 +12460,8 @@ namespace ts {
1246012460
if (containingMessageChain) {
1246112461
const chain = containingMessageChain();
1246212462
if (chain) {
12463-
errorInfo = concatenateDiagnosticMessageChains(chain, errorInfo);
12463+
concatenateDiagnosticMessageChains(chain, errorInfo);
12464+
errorInfo = chain;
1246412465
}
1246512466
}
1246612467

@@ -21655,7 +21656,7 @@ namespace ts {
2165521656
}
2165621657

2165721658
const related = max > 1 ? allDiagnostics[minIndex] : flatten(allDiagnostics);
21658-
diagnostics.add(createDiagnosticForNodeFromMessageChain(node, chainDiagnosticMessages(/*details*/ undefined, Diagnostics.No_overload_matches_this_call), related));
21659+
diagnostics.add(createDiagnosticForNodeFromMessageChain(node, chainDiagnosticMessages(undefined, Diagnostics.No_overload_matches_this_call), related));
2165921660
}
2166021661
}
2166121662
else if (candidateForArgumentArityError) {

src/compiler/program.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -502,30 +502,30 @@ namespace ts {
502502
return output;
503503
}
504504

505-
export function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain | undefined, newLine: string): string {
506-
if (isString(messageText)) {
507-
return messageText;
505+
export function flattenDiagnosticMessageText(diag: string | DiagnosticMessageChain | undefined, newLine: string, indent = 0): string {
506+
if (isString(diag)) {
507+
return diag;
508508
}
509-
else {
510-
let diagnosticChain = messageText;
511-
let result = "";
512-
513-
let indent = 0;
514-
while (diagnosticChain) {
515-
if (indent) {
516-
result += newLine;
509+
else if (diag === undefined) {
510+
return "";
511+
}
512+
let result = "";
513+
if (indent) {
514+
result += newLine;
517515

518-
for (let i = 0; i < indent; i++) {
519-
result += " ";
520-
}
521-
}
522-
result += diagnosticChain.messageText;
523-
indent++;
524-
diagnosticChain = diagnosticChain.next;
516+
for (let i = 0; i < indent; i++) {
517+
result += " ";
518+
}
519+
}
520+
result += diag.messageText;
521+
indent++;
522+
if (diag.next) {
523+
// TODO: Should be possible to optimise the common, non-tree case
524+
for (const kid of diag.next) {
525+
result += flattenDiagnosticMessageText(kid, newLine, indent);
525526
}
526-
527-
return result;
528527
}
528+
return result;
529529
}
530530

531531
/* @internal */

src/compiler/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4561,7 +4561,7 @@ namespace ts {
45614561
messageText: string;
45624562
category: DiagnosticCategory;
45634563
code: number;
4564-
next?: DiagnosticMessageChain;
4564+
next?: DiagnosticMessageChain[];
45654565
}
45664566

45674567
export interface Diagnostic extends DiagnosticRelatedInformation {

src/compiler/utilities.ts

Lines changed: 65 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7112,8 +7112,8 @@ namespace ts {
71127112
};
71137113
}
71147114

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

71197119
if (arguments.length > 2) {
@@ -7125,18 +7125,17 @@ namespace ts {
71257125
category: message.category,
71267126
code: message.code,
71277127

7128-
next: details
7128+
next: details === undefined || Array.isArray(details) ? details : [details]
71297129
};
71307130
}
71317131

7132-
export function concatenateDiagnosticMessageChains(headChain: DiagnosticMessageChain, tailChain: DiagnosticMessageChain): DiagnosticMessageChain {
7132+
export function concatenateDiagnosticMessageChains(headChain: DiagnosticMessageChain, tailChain: DiagnosticMessageChain): void {
71337133
let lastChain = headChain;
71347134
while (lastChain.next) {
7135-
lastChain = lastChain.next;
7135+
lastChain = lastChain.next[0];
71367136
}
71377137

7138-
lastChain.next = tailChain;
7139-
return headChain;
7138+
lastChain.next = [tailChain];
71407139
}
71417140

71427141
function getDiagnosticFilePath(diagnostic: Diagnostic): string | undefined {
@@ -7171,30 +7170,70 @@ namespace ts {
71717170
return d1.relatedInformation ? Comparison.LessThan : Comparison.GreaterThan;
71727171
}
71737172

7173+
// function compareMessageText(t1: string | DiagnosticMessageChain[], t2: string | DiagnosticMessageChain[]): Comparison {
7174+
// if (typeof t1 === 'string' && typeof t2 === 'string') {
7175+
// return compareStringsCaseSensitive(t1, t2)
7176+
// }
7177+
// else if (Array.isArray(t1) && Array.isArray(t2)) {
7178+
// if (t1.length < t2.length) {
7179+
// return Comparison.LessThan;
7180+
// }
7181+
// else if (t1.length > t2.length) {
7182+
// return Comparison.GreaterThan;
7183+
// }
7184+
// else {
7185+
// for (let i = 0; i < t1.length; i++) {
7186+
// t1[i].messageText
7187+
// const res = cmps(t1[i], t2[i]);
7188+
// if (res) {
7189+
// return res;
7190+
// }
7191+
// }
7192+
// return Comparison.EqualTo;
7193+
// }
7194+
// }
7195+
// else if (typeof t1 === 'string') {
7196+
// return Comparison.LessThan;
7197+
// }
7198+
// else {
7199+
// return Comparison.GreaterThan;
7200+
// }
7201+
// }
7202+
71747203
function compareMessageText(t1: string | DiagnosticMessageChain, t2: string | DiagnosticMessageChain): Comparison {
7175-
let text1: string | DiagnosticMessageChain | undefined = t1;
7176-
let text2: string | DiagnosticMessageChain | undefined = t2;
7177-
while (text1 && text2) {
7178-
// We still have both chains.
7179-
const string1 = isString(text1) ? text1 : text1.messageText;
7180-
const string2 = isString(text2) ? text2 : text2.messageText;
7181-
7182-
const res = compareStringsCaseSensitive(string1, string2);
7204+
if (typeof t1 === 'string' && typeof t2 === 'string') {
7205+
return compareStringsCaseSensitive(t1, t2);
7206+
}
7207+
else if (typeof t1 === 'string') {
7208+
return Comparison.LessThan;
7209+
}
7210+
else if (typeof t2 === 'string') {
7211+
return Comparison.GreaterThan;
7212+
}
7213+
let res = compareStringsCaseSensitive(t1.messageText, t2.messageText);
7214+
if (res) {
7215+
return res;
7216+
}
7217+
if (!t1.next && !t2.next) {
7218+
return Comparison.EqualTo;
7219+
}
7220+
if (!t1.next) {
7221+
return Comparison.LessThan;
7222+
}
7223+
if (!t2.next) {
7224+
return Comparison.GreaterThan;
7225+
}
7226+
res = compareValues(t1.next.length, t2.next.length);
7227+
if (res) {
7228+
return res;
7229+
}
7230+
for (let i = 0; i < t1.next.length; i++) {
7231+
res = compareMessageText(t1.next[i], t2.next[i])
71837232
if (res) {
71847233
return res;
71857234
}
7186-
7187-
text1 = isString(text1) ? undefined : text1.next;
7188-
text2 = isString(text2) ? undefined : text2.next;
71897235
}
7190-
7191-
if (!text1 && !text2) {
7192-
// if the chains are done, then these messages are the same.
7193-
return Comparison.EqualTo;
7194-
}
7195-
7196-
// We still have one chain remaining. The shorter chain should come first.
7197-
return text1 ? Comparison.GreaterThan : Comparison.LessThan;
7236+
return Comparison.EqualTo;
71987237
}
71997238

72007239
export function getEmitScriptTarget(compilerOptions: CompilerOptions) {

src/harness/fourslash.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,13 +1482,7 @@ Actual: ${stringify(fullActual)}`);
14821482
const diagnostics = ts.getPreEmitDiagnostics(this.languageService.getProgram()!); // TODO: GH#18217
14831483
for (const diagnostic of diagnostics) {
14841484
if (!ts.isString(diagnostic.messageText)) {
1485-
let chainedMessage: ts.DiagnosticMessageChain | undefined = diagnostic.messageText;
1486-
let indentation = " ";
1487-
while (chainedMessage) {
1488-
resultString += indentation + chainedMessage.messageText + Harness.IO.newLine();
1489-
chainedMessage = chainedMessage.next;
1490-
indentation = indentation + " ";
1491-
}
1485+
resultString += this.flattenChainedMessage(diagnostic.messageText);
14921486
}
14931487
else {
14941488
resultString += " " + diagnostic.messageText + Harness.IO.newLine();
@@ -1506,6 +1500,17 @@ Actual: ${stringify(fullActual)}`);
15061500
Harness.Baseline.runBaseline(ts.Debug.assertDefined(this.testData.globalOptions[MetadataOptionNames.baselineFile]), resultString);
15071501
}
15081502

1503+
private flattenChainedMessage(diag: ts.DiagnosticMessageChain, indent = " ") {
1504+
let result = "";
1505+
result += indent + diag.messageText + Harness.IO.newLine();
1506+
if (diag.next) {
1507+
for (const kid of diag.next) {
1508+
result += this.flattenChainedMessage(kid, indent + " ");
1509+
}
1510+
}
1511+
return result;
1512+
}
1513+
15091514
public baselineQuickInfo() {
15101515
const baselineFile = this.getBaselineFileName();
15111516
Harness.Baseline.runBaseline(

0 commit comments

Comments
 (0)