From d2ad3ca035803c1dc9a5c5b48ae05c6364f42e20 Mon Sep 17 00:00:00 2001 From: Gabriela Araujo Britto Date: Mon, 29 Apr 2024 10:24:22 -0700 Subject: [PATCH] Improve diagnostics deduplication 2 (#58318) --- src/compiler/checker.ts | 22 +++++- src/compiler/types.ts | 17 +++++ src/compiler/utilities.ts | 67 ++++++++++++++----- .../duplicateErrorAssignability.errors.txt | 22 ++++++ .../reference/duplicateErrorAssignability.js | 21 ++++++ .../duplicateErrorAssignability.symbols | 38 +++++++++++ .../duplicateErrorAssignability.types | 52 ++++++++++++++ .../duplicateErrorNameNotFound.errors.txt | 11 +++ .../reference/duplicateErrorNameNotFound.js | 12 ++++ .../duplicateErrorNameNotFound.symbols | 10 +++ .../duplicateErrorNameNotFound.types | 12 ++++ .../mappedTypeRecursiveInference.types | 2 +- .../reusing-type-ref-resolution.js | 30 ++++++--- .../compiler/duplicateErrorAssignability.ts | 14 ++++ .../compiler/duplicateErrorNameNotFound.ts | 7 ++ 15 files changed, 310 insertions(+), 27 deletions(-) create mode 100644 tests/baselines/reference/duplicateErrorAssignability.errors.txt create mode 100644 tests/baselines/reference/duplicateErrorAssignability.js create mode 100644 tests/baselines/reference/duplicateErrorAssignability.symbols create mode 100644 tests/baselines/reference/duplicateErrorAssignability.types create mode 100644 tests/baselines/reference/duplicateErrorNameNotFound.errors.txt create mode 100644 tests/baselines/reference/duplicateErrorNameNotFound.js create mode 100644 tests/baselines/reference/duplicateErrorNameNotFound.symbols create mode 100644 tests/baselines/reference/duplicateErrorNameNotFound.types create mode 100644 tests/cases/compiler/duplicateErrorAssignability.ts create mode 100644 tests/cases/compiler/duplicateErrorNameNotFound.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8aef6d5d08e5e..ba85f4ab655fc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -251,6 +251,7 @@ import { getAssignmentDeclarationKind, getAssignmentDeclarationPropertyAccessKind, getAssignmentTargetKind, + getCanonicalDiagnostic, getCheckFlags, getClassExtendsHeritageElement, getClassLikeDeclarationOfSymbol, @@ -3118,10 +3119,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (suggestion) { const suggestionName = symbolToString(suggestion); const isUncheckedJS = isUncheckedJSSuggestion(errorLocation, suggestion, /*excludeClasses*/ false); - const message = meaning === SymbolFlags.Namespace || nameArg && typeof nameArg !== "string" && nodeIsSynthesized(nameArg) ? Diagnostics.Cannot_find_namespace_0_Did_you_mean_1 + const message = meaning === SymbolFlags.Namespace || + nameArg && typeof nameArg !== "string" && nodeIsSynthesized(nameArg) ? + Diagnostics.Cannot_find_namespace_0_Did_you_mean_1 : isUncheckedJS ? Diagnostics.Could_not_find_name_0_Did_you_mean_1 : Diagnostics.Cannot_find_name_0_Did_you_mean_1; const diagnostic = createError(errorLocation, message, diagnosticName(nameArg), suggestionName); + diagnostic.canonicalHead = getCanonicalDiagnostic(nameNotFoundMessage, diagnosticName(nameArg)); addErrorOrSuggestion(!isUncheckedJS, diagnostic); if (suggestion.valueDeclaration) { addRelatedInfo( @@ -21697,9 +21701,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { errorInfo = elaborateNeverIntersection(errorInfo, originalTarget); } + // Used by, eg, missing property checking to replace the top-level message with a more informative one. if (!headMessage && maybeSuppress) { + // We suppress a call to `reportRelationError` or not depending on the state of the type checker, so + // we call `reportRelationError` here and then undo its effects to figure out what would be the diagnostic + // if we hadn't supress it, and save that as a canonical diagnostic for deduplication purposes. + const savedErrorState = captureErrorCalculationState(); + reportRelationError(headMessage, source, target); + let canonical; + if (errorInfo && errorInfo !== savedErrorState.errorInfo) { + canonical = { code: errorInfo.code, messageText: errorInfo.messageText }; + } + resetErrorInfo(savedErrorState); + if (canonical && errorInfo) { + errorInfo.canonicalHead = canonical; + } + lastSkippedInfo = [source, target]; - // Used by, eg, missing property checking to replace the top-level message with a more informative one return; } reportRelationError(headMessage, source, target); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 78772436ca687..de84a65032b62 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -7069,6 +7069,8 @@ export interface DiagnosticMessageChain { next?: DiagnosticMessageChain[]; /** @internal */ repopulateInfo?: () => RepopulateDiagnosticChainInfo; + /** @internal */ + canonicalHead?: CanonicalDiagnostic; } export interface Diagnostic extends DiagnosticRelatedInformation { @@ -7079,6 +7081,21 @@ export interface Diagnostic extends DiagnosticRelatedInformation { source?: string; relatedInformation?: DiagnosticRelatedInformation[]; /** @internal */ skippedOn?: keyof CompilerOptions; + /** + * @internal + * Used for deduplication and comparison. + * Whenever it is possible for two diagnostics that report the same problem to be produced with + * different messages (e.g. "Cannot find name 'foo'" vs "Cannot find name 'foo'. Did you mean 'bar'?"), + * this property can be set to a canonical message, + * so that those two diagnostics are appropriately considered to be the same. + */ + canonicalHead?: CanonicalDiagnostic; +} + +/** @internal */ +export interface CanonicalDiagnostic { + code: number; + messageText: string; } /** @internal */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 867a139c5c8c6..345ccedcb59dd 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -41,6 +41,7 @@ import { canHaveLocals, canHaveModifiers, type CanHaveModuleSpecifier, + CanonicalDiagnostic, CaseBlock, CaseClause, CaseOrDefaultClause, @@ -2178,6 +2179,7 @@ export function createFileDiagnosticFromMessageChain(file: SourceFile, start: nu category: messageChain.category, messageText: messageChain.next ? messageChain : messageChain.messageText, relatedInformation, + canonicalHead: messageChain.canonicalHead, }; } @@ -2216,6 +2218,14 @@ export function createDiagnosticForRange(sourceFile: SourceFile, range: TextRang }; } +/** @internal */ +export function getCanonicalDiagnostic(message: DiagnosticMessage, ...args: string[]): CanonicalDiagnostic { + return { + code: message.code, + messageText: formatMessage(message, ...args), + }; +} + /** @internal */ export function getSpanOfTokenAtPosition(sourceFile: SourceFile, pos: number): TextSpan { const scanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/ true, sourceFile.languageVariant, sourceFile.text, /*onError*/ undefined, pos); @@ -8540,11 +8550,13 @@ export function compareDiagnostics(d1: Diagnostic, d2: Diagnostic): Comparison { /** @internal */ export function compareDiagnosticsSkipRelatedInformation(d1: Diagnostic, d2: Diagnostic): Comparison { + const code1 = getDiagnosticCode(d1); + const code2 = getDiagnosticCode(d2); return compareStringsCaseSensitive(getDiagnosticFilePath(d1), getDiagnosticFilePath(d2)) || compareValues(d1.start, d2.start) || compareValues(d1.length, d2.length) || - compareValues(d1.code, d2.code) || - compareMessageText(d1.messageText, d2.messageText) || + compareValues(code1, code2) || + compareMessageText(d1, d2) || Comparison.EqualTo; } @@ -8566,25 +8578,38 @@ function compareRelatedInformation(d1: Diagnostic, d2: Diagnostic): Comparison { // An diagnostic message with more elaboration should be considered *less than* a diagnostic message // with less elaboration that is otherwise similar. function compareMessageText( - t1: string | Pick, - t2: string | Pick, + d1: Diagnostic, + d2: Diagnostic, ): Comparison { - if (typeof t1 === "string" && typeof t2 === "string") { - return compareStringsCaseSensitive(t1, t2); + let headMsg1 = getDiagnosticMessage(d1); + let headMsg2 = getDiagnosticMessage(d2); + if (typeof headMsg1 !== "string") { + headMsg1 = headMsg1.messageText; } - - if (typeof t1 === "string") { - t1 = { messageText: t1 }; + if (typeof headMsg2 !== "string") { + headMsg2 = headMsg2.messageText; } - if (typeof t2 === "string") { - t2 = { messageText: t2 }; + const chain1 = typeof d1.messageText !== "string" ? d1.messageText.next : undefined; + const chain2 = typeof d2.messageText !== "string" ? d2.messageText.next : undefined; + + let res = compareStringsCaseSensitive(headMsg1, headMsg2); + if (res) { + return res; } - const res = compareStringsCaseSensitive(t1.messageText, t2.messageText); + + res = compareMessageChain(chain1, chain2); if (res) { return res; } - return compareMessageChain(t1.next, t2.next); + if (d1.canonicalHead && !d2.canonicalHead) { + return Comparison.LessThan; + } + if (d2.canonicalHead && !d1.canonicalHead) { + return Comparison.GreaterThan; + } + + return Comparison.EqualTo; } // First compare by size of the message chain, @@ -8659,11 +8684,23 @@ function compareMessageChainContent( /** @internal */ export function diagnosticsEqualityComparer(d1: Diagnostic, d2: Diagnostic): boolean { + const code1 = getDiagnosticCode(d1); + const code2 = getDiagnosticCode(d2); + const msg1 = getDiagnosticMessage(d1); + const msg2 = getDiagnosticMessage(d2); return compareStringsCaseSensitive(getDiagnosticFilePath(d1), getDiagnosticFilePath(d2)) === Comparison.EqualTo && compareValues(d1.start, d2.start) === Comparison.EqualTo && compareValues(d1.length, d2.length) === Comparison.EqualTo && - compareValues(d1.code, d2.code) === Comparison.EqualTo && - messageTextEqualityComparer(d1.messageText, d2.messageText); + compareValues(code1, code2) === Comparison.EqualTo && + messageTextEqualityComparer(msg1, msg2); +} + +function getDiagnosticCode(d: Diagnostic): number { + return d.canonicalHead?.code || d.code; +} + +function getDiagnosticMessage(d: Diagnostic): string | DiagnosticMessageChain { + return d.canonicalHead?.messageText || d.messageText; } function messageTextEqualityComparer(m1: string | DiagnosticMessageChain, m2: string | DiagnosticMessageChain): boolean { diff --git a/tests/baselines/reference/duplicateErrorAssignability.errors.txt b/tests/baselines/reference/duplicateErrorAssignability.errors.txt new file mode 100644 index 0000000000000..3b332cf0c116d --- /dev/null +++ b/tests/baselines/reference/duplicateErrorAssignability.errors.txt @@ -0,0 +1,22 @@ +duplicateErrorAssignability.ts(10,11): error TS2741: Property 'x' is missing in type 'B' but required in type 'A'. +duplicateErrorAssignability.ts(12,5): error TS2538: Type 'B' cannot be used as an index type. + + +==== duplicateErrorAssignability.ts (2 errors) ==== + interface A { + x: number; + } + interface B { + y: string; + } + + declare let b: B; + declare let a: A; + const x = a = b; + ~ +!!! error TS2741: Property 'x' is missing in type 'B' but required in type 'A'. +!!! related TS2728 duplicateErrorAssignability.ts:2:5: 'x' is declared here. + let obj: { 3: string } = { 3: "three" }; + obj[x]; + ~ +!!! error TS2538: Type 'B' cannot be used as an index type. \ No newline at end of file diff --git a/tests/baselines/reference/duplicateErrorAssignability.js b/tests/baselines/reference/duplicateErrorAssignability.js new file mode 100644 index 0000000000000..21a31474f939b --- /dev/null +++ b/tests/baselines/reference/duplicateErrorAssignability.js @@ -0,0 +1,21 @@ +//// [tests/cases/compiler/duplicateErrorAssignability.ts] //// + +//// [duplicateErrorAssignability.ts] +interface A { + x: number; +} +interface B { + y: string; +} + +declare let b: B; +declare let a: A; +const x = a = b; +let obj: { 3: string } = { 3: "three" }; +obj[x]; + +//// [duplicateErrorAssignability.js] +"use strict"; +var x = a = b; +var obj = { 3: "three" }; +obj[x]; diff --git a/tests/baselines/reference/duplicateErrorAssignability.symbols b/tests/baselines/reference/duplicateErrorAssignability.symbols new file mode 100644 index 0000000000000..014c0be74da41 --- /dev/null +++ b/tests/baselines/reference/duplicateErrorAssignability.symbols @@ -0,0 +1,38 @@ +//// [tests/cases/compiler/duplicateErrorAssignability.ts] //// + +=== duplicateErrorAssignability.ts === +interface A { +>A : Symbol(A, Decl(duplicateErrorAssignability.ts, 0, 0)) + + x: number; +>x : Symbol(A.x, Decl(duplicateErrorAssignability.ts, 0, 13)) +} +interface B { +>B : Symbol(B, Decl(duplicateErrorAssignability.ts, 2, 1)) + + y: string; +>y : Symbol(B.y, Decl(duplicateErrorAssignability.ts, 3, 13)) +} + +declare let b: B; +>b : Symbol(b, Decl(duplicateErrorAssignability.ts, 7, 11)) +>B : Symbol(B, Decl(duplicateErrorAssignability.ts, 2, 1)) + +declare let a: A; +>a : Symbol(a, Decl(duplicateErrorAssignability.ts, 8, 11)) +>A : Symbol(A, Decl(duplicateErrorAssignability.ts, 0, 0)) + +const x = a = b; +>x : Symbol(x, Decl(duplicateErrorAssignability.ts, 9, 5)) +>a : Symbol(a, Decl(duplicateErrorAssignability.ts, 8, 11)) +>b : Symbol(b, Decl(duplicateErrorAssignability.ts, 7, 11)) + +let obj: { 3: string } = { 3: "three" }; +>obj : Symbol(obj, Decl(duplicateErrorAssignability.ts, 10, 3)) +>3 : Symbol(3, Decl(duplicateErrorAssignability.ts, 10, 10)) +>3 : Symbol(3, Decl(duplicateErrorAssignability.ts, 10, 26)) + +obj[x]; +>obj : Symbol(obj, Decl(duplicateErrorAssignability.ts, 10, 3)) +>x : Symbol(x, Decl(duplicateErrorAssignability.ts, 9, 5)) + diff --git a/tests/baselines/reference/duplicateErrorAssignability.types b/tests/baselines/reference/duplicateErrorAssignability.types new file mode 100644 index 0000000000000..ff866cb641f7a --- /dev/null +++ b/tests/baselines/reference/duplicateErrorAssignability.types @@ -0,0 +1,52 @@ +//// [tests/cases/compiler/duplicateErrorAssignability.ts] //// + +=== duplicateErrorAssignability.ts === +interface A { + x: number; +>x : number +> : ^^^^^^ +} +interface B { + y: string; +>y : string +> : ^^^^^^ +} + +declare let b: B; +>b : B +> : ^ + +declare let a: A; +>a : A +> : ^ + +const x = a = b; +>x : B +> : ^ +>a = b : B +> : ^ +>a : A +> : ^ +>b : B +> : ^ + +let obj: { 3: string } = { 3: "three" }; +>obj : { 3: string; } +> : ^^^^^ ^^^ +>3 : string +> : ^^^^^^ +>{ 3: "three" } : { 3: string; } +> : ^^^^^^^^^^^^^^ +>3 : string +> : ^^^^^^ +>"three" : "three" +> : ^^^^^^^ + +obj[x]; +>obj[x] : any +> : ^^^ +>obj : { 3: string; } +> : ^^^^^^^^^^^^^^ +>x : B +> : ^ + diff --git a/tests/baselines/reference/duplicateErrorNameNotFound.errors.txt b/tests/baselines/reference/duplicateErrorNameNotFound.errors.txt new file mode 100644 index 0000000000000..b30ab1a7b3d13 --- /dev/null +++ b/tests/baselines/reference/duplicateErrorNameNotFound.errors.txt @@ -0,0 +1,11 @@ +duplicateErrorNameNotFound.ts(4,5): error TS2552: Cannot find name 'RoomInterface'. Did you mean 'RoomInterfae'? + + +==== duplicateErrorNameNotFound.ts (1 errors) ==== + type RoomInterfae = {}; + + export type { + RoomInterface + ~~~~~~~~~~~~~ +!!! error TS2552: Cannot find name 'RoomInterface'. Did you mean 'RoomInterfae'? + } \ No newline at end of file diff --git a/tests/baselines/reference/duplicateErrorNameNotFound.js b/tests/baselines/reference/duplicateErrorNameNotFound.js new file mode 100644 index 0000000000000..674c29ce66e08 --- /dev/null +++ b/tests/baselines/reference/duplicateErrorNameNotFound.js @@ -0,0 +1,12 @@ +//// [tests/cases/compiler/duplicateErrorNameNotFound.ts] //// + +//// [duplicateErrorNameNotFound.ts] +type RoomInterfae = {}; + +export type { + RoomInterface +} + +//// [duplicateErrorNameNotFound.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/tests/baselines/reference/duplicateErrorNameNotFound.symbols b/tests/baselines/reference/duplicateErrorNameNotFound.symbols new file mode 100644 index 0000000000000..7cff4df8ba8a5 --- /dev/null +++ b/tests/baselines/reference/duplicateErrorNameNotFound.symbols @@ -0,0 +1,10 @@ +//// [tests/cases/compiler/duplicateErrorNameNotFound.ts] //// + +=== duplicateErrorNameNotFound.ts === +type RoomInterfae = {}; +>RoomInterfae : Symbol(RoomInterfae, Decl(duplicateErrorNameNotFound.ts, 0, 0)) + +export type { + RoomInterface +>RoomInterface : Symbol(RoomInterface, Decl(duplicateErrorNameNotFound.ts, 2, 13)) +} diff --git a/tests/baselines/reference/duplicateErrorNameNotFound.types b/tests/baselines/reference/duplicateErrorNameNotFound.types new file mode 100644 index 0000000000000..a1ccbc6d52b1b --- /dev/null +++ b/tests/baselines/reference/duplicateErrorNameNotFound.types @@ -0,0 +1,12 @@ +//// [tests/cases/compiler/duplicateErrorNameNotFound.ts] //// + +=== duplicateErrorNameNotFound.ts === +type RoomInterfae = {}; +>RoomInterfae : RoomInterfae +> : ^^^^^^^^^^^^ + +export type { + RoomInterface +>RoomInterface : any +> : ^^^ +} diff --git a/tests/baselines/reference/mappedTypeRecursiveInference.types b/tests/baselines/reference/mappedTypeRecursiveInference.types index b90ce7da3d797..03b70ec3cc79a 100644 --- a/tests/baselines/reference/mappedTypeRecursiveInference.types +++ b/tests/baselines/reference/mappedTypeRecursiveInference.types @@ -4,7 +4,7 @@ Assignability cache: 5,000 Type Count: 10,000 Instantiation count: 250,000 -Symbol count: 100,000 +Symbol count: 250,000 === mappedTypeRecursiveInference.ts === interface A { a: A } diff --git a/tests/baselines/reference/tscWatch/resolutionCache/reusing-type-ref-resolution.js b/tests/baselines/reference/tscWatch/resolutionCache/reusing-type-ref-resolution.js index 1ec53c5791705..6ff0ba14b1f4c 100644 --- a/tests/baselines/reference/tscWatch/resolutionCache/reusing-type-ref-resolution.js +++ b/tests/baselines/reference/tscWatch/resolutionCache/reusing-type-ref-resolution.js @@ -211,7 +211,7 @@ export {}; //// [/users/username/projects/project/outDir/tsconfig.tsbuildinfo] -{"program":{"fileNames":["../../../../../a/lib/lib.d.ts","../node_modules/pkg0/index.d.ts","../filewithimports.ts","../node_modules/pkg2/index.d.ts","../filewithtyperefs.ts"],"fileInfos":[{"version":"-7698705165-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }","affectsGlobalScope":true,"impliedFormat":1},{"version":"-8124756421-export interface Import0 {}","impliedFormat":1},{"version":"-14287751515-import type { Import0 } from \"pkg0\";\nimport type { Import1 } from \"pkg1\";\n","signature":"-3531856636-export {};\n","impliedFormat":1},{"version":"-11273315461-interface Import2 {}","affectsGlobalScope":true,"impliedFormat":1},{"version":"-12735305811-/// \n/// \ninterface LocalInterface extends Import2, Import3 {}\nexport {}\n","signature":"-3531856636-export {};\n","impliedFormat":1}],"root":[3,5],"options":{"composite":true,"outDir":"./"},"fileIdsList":[[2],[4]],"referencedMap":[[3,1],[5,2]],"semanticDiagnosticsPerFile":[1,[3,[{"file":"../filewithimports.ts","start":66,"length":6,"messageText":"Cannot find module 'pkg1' or its corresponding type declarations.","category":1,"code":2307}]],[5,[{"file":"../filewithtyperefs.ts","start":102,"length":7,"messageText":"Cannot find name 'Import3'. Did you mean 'Import2'?","category":1,"code":2552}]],2,4],"latestChangedDtsFile":"./fileWithTypeRefs.d.ts"},"version":"FakeTSVersion"} +{"program":{"fileNames":["../../../../../a/lib/lib.d.ts","../node_modules/pkg0/index.d.ts","../filewithimports.ts","../node_modules/pkg2/index.d.ts","../filewithtyperefs.ts"],"fileInfos":[{"version":"-7698705165-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }","affectsGlobalScope":true,"impliedFormat":1},{"version":"-8124756421-export interface Import0 {}","impliedFormat":1},{"version":"-14287751515-import type { Import0 } from \"pkg0\";\nimport type { Import1 } from \"pkg1\";\n","signature":"-3531856636-export {};\n","impliedFormat":1},{"version":"-11273315461-interface Import2 {}","affectsGlobalScope":true,"impliedFormat":1},{"version":"-12735305811-/// \n/// \ninterface LocalInterface extends Import2, Import3 {}\nexport {}\n","signature":"-3531856636-export {};\n","impliedFormat":1}],"root":[3,5],"options":{"composite":true,"outDir":"./"},"fileIdsList":[[2],[4]],"referencedMap":[[3,1],[5,2]],"semanticDiagnosticsPerFile":[1,[3,[{"file":"../filewithimports.ts","start":66,"length":6,"messageText":"Cannot find module 'pkg1' or its corresponding type declarations.","category":1,"code":2307}]],[5,[{"file":"../filewithtyperefs.ts","start":102,"length":7,"messageText":"Cannot find name 'Import3'. Did you mean 'Import2'?","category":1,"code":2552,"canonicalHead":{"code":2304,"messageText":"Cannot find name 'Import3'."}}]],2,4],"latestChangedDtsFile":"./fileWithTypeRefs.d.ts"},"version":"FakeTSVersion"} //// [/users/username/projects/project/outDir/tsconfig.tsbuildinfo.readable.baseline.txt] { @@ -330,7 +330,11 @@ export {}; "length": 7, "messageText": "Cannot find name 'Import3'. Did you mean 'Import2'?", "category": 1, - "code": 2552 + "code": 2552, + "canonicalHead": { + "code": 2304, + "messageText": "Cannot find name 'Import3'." + } } ] ], @@ -340,7 +344,7 @@ export {}; "latestChangedDtsFile": "./fileWithTypeRefs.d.ts" }, "version": "FakeTSVersion", - "size": 1698 + "size": 1772 } @@ -576,7 +580,7 @@ fileWithTypeRefs.ts //// [/users/username/projects/project/outDir/fileWithImports.js] file written with same contents //// [/users/username/projects/project/outDir/tsconfig.tsbuildinfo] -{"program":{"fileNames":["../../../../../a/lib/lib.d.ts","../node_modules/pkg0/index.d.ts","../node_modules/pkg1/index.d.ts","../filewithimports.ts","../node_modules/pkg2/index.d.ts","../filewithtyperefs.ts"],"fileInfos":[{"version":"-7698705165-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }","affectsGlobalScope":true,"impliedFormat":1},{"version":"-8124756421-export interface Import0 {}","impliedFormat":1},{"version":"-8124720484-export interface Import1 {}","impliedFormat":1},{"version":"-14287751515-import type { Import0 } from \"pkg0\";\nimport type { Import1 } from \"pkg1\";\n","signature":"-3531856636-export {};\n","impliedFormat":1},{"version":"-11273315461-interface Import2 {}","affectsGlobalScope":true,"impliedFormat":1},{"version":"-12735305811-/// \n/// \ninterface LocalInterface extends Import2, Import3 {}\nexport {}\n","signature":"-3531856636-export {};\n","impliedFormat":1}],"root":[4,6],"options":{"composite":true,"outDir":"./"},"fileIdsList":[[2,3],[5]],"referencedMap":[[4,1],[6,2]],"semanticDiagnosticsPerFile":[1,4,[6,[{"file":"../filewithtyperefs.ts","start":102,"length":7,"messageText":"Cannot find name 'Import3'. Did you mean 'Import2'?","category":1,"code":2552}]],2,3,5],"latestChangedDtsFile":"./fileWithTypeRefs.d.ts"},"version":"FakeTSVersion"} +{"program":{"fileNames":["../../../../../a/lib/lib.d.ts","../node_modules/pkg0/index.d.ts","../node_modules/pkg1/index.d.ts","../filewithimports.ts","../node_modules/pkg2/index.d.ts","../filewithtyperefs.ts"],"fileInfos":[{"version":"-7698705165-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }","affectsGlobalScope":true,"impliedFormat":1},{"version":"-8124756421-export interface Import0 {}","impliedFormat":1},{"version":"-8124720484-export interface Import1 {}","impliedFormat":1},{"version":"-14287751515-import type { Import0 } from \"pkg0\";\nimport type { Import1 } from \"pkg1\";\n","signature":"-3531856636-export {};\n","impliedFormat":1},{"version":"-11273315461-interface Import2 {}","affectsGlobalScope":true,"impliedFormat":1},{"version":"-12735305811-/// \n/// \ninterface LocalInterface extends Import2, Import3 {}\nexport {}\n","signature":"-3531856636-export {};\n","impliedFormat":1}],"root":[4,6],"options":{"composite":true,"outDir":"./"},"fileIdsList":[[2,3],[5]],"referencedMap":[[4,1],[6,2]],"semanticDiagnosticsPerFile":[1,4,[6,[{"file":"../filewithtyperefs.ts","start":102,"length":7,"messageText":"Cannot find name 'Import3'. Did you mean 'Import2'?","category":1,"code":2552,"canonicalHead":{"code":2304,"messageText":"Cannot find name 'Import3'."}}]],2,3,5],"latestChangedDtsFile":"./fileWithTypeRefs.d.ts"},"version":"FakeTSVersion"} //// [/users/username/projects/project/outDir/tsconfig.tsbuildinfo.readable.baseline.txt] { @@ -695,7 +699,11 @@ fileWithTypeRefs.ts "length": 7, "messageText": "Cannot find name 'Import3'. Did you mean 'Import2'?", "category": 1, - "code": 2552 + "code": 2552, + "canonicalHead": { + "code": 2304, + "messageText": "Cannot find name 'Import3'." + } } ] ], @@ -706,7 +714,7 @@ fileWithTypeRefs.ts "latestChangedDtsFile": "./fileWithTypeRefs.d.ts" }, "version": "FakeTSVersion", - "size": 1642 + "size": 1716 } @@ -954,7 +962,7 @@ fileWithTypeRefs.ts //// [/users/username/projects/project/outDir/fileWithTypeRefs.js] file written with same contents //// [/users/username/projects/project/outDir/tsconfig.tsbuildinfo] -{"program":{"fileNames":["../../../../../a/lib/lib.d.ts","../node_modules/pkg0/index.d.ts","../node_modules/pkg1/index.d.ts","../filewithimports.ts","../node_modules/pkg2/index.d.ts","../node_modules/pkg3/index.d.ts","../filewithtyperefs.ts"],"fileInfos":[{"version":"-7698705165-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }","affectsGlobalScope":true,"impliedFormat":1},{"version":"-8124756421-export interface Import0 {}","impliedFormat":1},{"version":"-8124720484-export interface Import1 {}","impliedFormat":1},{"version":"-14287751515-import type { Import0 } from \"pkg0\";\nimport type { Import1 } from \"pkg1\";\n","signature":"-3531856636-export {};\n","impliedFormat":1},{"version":"-11273315461-interface Import2 {}","affectsGlobalScope":true,"impliedFormat":1},{"version":"-8124648610-export interface Import3 {}","impliedFormat":1},{"version":"-12735305811-/// \n/// \ninterface LocalInterface extends Import2, Import3 {}\nexport {}\n","signature":"-3531856636-export {};\n","impliedFormat":1}],"root":[4,7],"options":{"composite":true,"outDir":"./"},"fileIdsList":[[2,3],[5,6]],"referencedMap":[[4,1],[7,2]],"semanticDiagnosticsPerFile":[1,4,[7,[{"file":"../filewithtyperefs.ts","start":102,"length":7,"messageText":"Cannot find name 'Import3'. Did you mean 'Import2'?","category":1,"code":2552}]],2,3,5,6],"latestChangedDtsFile":"./fileWithTypeRefs.d.ts"},"version":"FakeTSVersion"} +{"program":{"fileNames":["../../../../../a/lib/lib.d.ts","../node_modules/pkg0/index.d.ts","../node_modules/pkg1/index.d.ts","../filewithimports.ts","../node_modules/pkg2/index.d.ts","../node_modules/pkg3/index.d.ts","../filewithtyperefs.ts"],"fileInfos":[{"version":"-7698705165-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }","affectsGlobalScope":true,"impliedFormat":1},{"version":"-8124756421-export interface Import0 {}","impliedFormat":1},{"version":"-8124720484-export interface Import1 {}","impliedFormat":1},{"version":"-14287751515-import type { Import0 } from \"pkg0\";\nimport type { Import1 } from \"pkg1\";\n","signature":"-3531856636-export {};\n","impliedFormat":1},{"version":"-11273315461-interface Import2 {}","affectsGlobalScope":true,"impliedFormat":1},{"version":"-8124648610-export interface Import3 {}","impliedFormat":1},{"version":"-12735305811-/// \n/// \ninterface LocalInterface extends Import2, Import3 {}\nexport {}\n","signature":"-3531856636-export {};\n","impliedFormat":1}],"root":[4,7],"options":{"composite":true,"outDir":"./"},"fileIdsList":[[2,3],[5,6]],"referencedMap":[[4,1],[7,2]],"semanticDiagnosticsPerFile":[1,4,[7,[{"file":"../filewithtyperefs.ts","start":102,"length":7,"messageText":"Cannot find name 'Import3'. Did you mean 'Import2'?","category":1,"code":2552,"canonicalHead":{"code":2304,"messageText":"Cannot find name 'Import3'."}}]],2,3,5,6],"latestChangedDtsFile":"./fileWithTypeRefs.d.ts"},"version":"FakeTSVersion"} //// [/users/username/projects/project/outDir/tsconfig.tsbuildinfo.readable.baseline.txt] { @@ -1085,7 +1093,11 @@ fileWithTypeRefs.ts "length": 7, "messageText": "Cannot find name 'Import3'. Did you mean 'Import2'?", "category": 1, - "code": 2552 + "code": 2552, + "canonicalHead": { + "code": 2304, + "messageText": "Cannot find name 'Import3'." + } } ] ], @@ -1097,7 +1109,7 @@ fileWithTypeRefs.ts "latestChangedDtsFile": "./fileWithTypeRefs.d.ts" }, "version": "FakeTSVersion", - "size": 1752 + "size": 1826 } diff --git a/tests/cases/compiler/duplicateErrorAssignability.ts b/tests/cases/compiler/duplicateErrorAssignability.ts new file mode 100644 index 0000000000000..f1e76e41ef402 --- /dev/null +++ b/tests/cases/compiler/duplicateErrorAssignability.ts @@ -0,0 +1,14 @@ +// @strict: true + +interface A { + x: number; +} +interface B { + y: string; +} + +declare let b: B; +declare let a: A; +const x = a = b; +let obj: { 3: string } = { 3: "three" }; +obj[x]; \ No newline at end of file diff --git a/tests/cases/compiler/duplicateErrorNameNotFound.ts b/tests/cases/compiler/duplicateErrorNameNotFound.ts new file mode 100644 index 0000000000000..f76acc25381ba --- /dev/null +++ b/tests/cases/compiler/duplicateErrorNameNotFound.ts @@ -0,0 +1,7 @@ +// @strict: true + +type RoomInterfae = {}; + +export type { + RoomInterface +} \ No newline at end of file