From 943fc5b0574c8b01e16dd6c27598ffdb9b3d87a2 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Tue, 25 Jan 2022 12:08:30 -0800 Subject: [PATCH 1/2] Add crashing test --- src/testRunner/unittests/tsc/incremental.ts | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/testRunner/unittests/tsc/incremental.ts b/src/testRunner/unittests/tsc/incremental.ts index a8fe334de7c7f..13a644a62082a 100644 --- a/src/testRunner/unittests/tsc/incremental.ts +++ b/src/testRunner/unittests/tsc/incremental.ts @@ -418,5 +418,36 @@ declare global { incrementalScenarios: noChangeOnlyRuns, baselinePrograms: true }); + + verifyTscSerializedIncrementalEdits({ + scenario: "incremental", + subScenario: "serializing error chains", + commandLineArgs: ["-p", `src/project`], + fs: () => loadProjectFromFiles({ + "/src/project/tsconfig.json": JSON.stringify({ + compilerOptions: { + incremental: true, + strict: true, + jsx: "react", + module: "esnext", + }, + }), + "/src/project/index.tsx": Utils.dedent` + declare namespace JSX { + interface ElementChildrenAttribute { children: {}; } + interface IntrinsicElements { div: {} } + } + + declare var React: any; + + declare function Component(props: never): any; + declare function Component(props: { children?: number }): any; + ( +
+
+ )` + }, `\ninterface ReadonlyArray { readonly length: number }`), + incrementalScenarios: noChangeOnlyRuns, + }); }); } From 85b945262fa21f7842c9ef65aa422be598dc340c Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Tue, 25 Jan 2022 14:37:25 -0800 Subject: [PATCH 2/2] Fix unsafe cast to DiagnosticMessageChain --- src/compiler/checker.ts | 2 +- src/compiler/utilities.ts | 9 + .../initial-build/serializing-error-chains.js | 185 ++++++++++++++++++ 3 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/tsc/incremental/initial-build/serializing-error-chains.js diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9c5beffc61130..88fd5a43469e4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30116,7 +30116,7 @@ namespace ts { const diags = max > 1 ? allDiagnostics[minIndex] : flatten(allDiagnostics); Debug.assert(diags.length > 0, "No errors reported for 3 or fewer overload signatures"); const chain = chainDiagnosticMessages( - map(diags, d => typeof d.messageText === "string" ? (d as DiagnosticMessageChain) : d.messageText), + map(diags, createDiagnosticMessageChainFromDiagnostic), Diagnostics.No_overload_matches_this_call); // The below is a spread to guarantee we get a new (mutable) array - our `flatMap` helper tries to do "smart" optimizations where it reuses input // arrays and the emptyArray singleton where possible, which is decidedly not what we want while we're still constructing this diagnostic diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index ed8ddf17227a0..9e8fbcf756c5e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1071,6 +1071,15 @@ namespace ts { }; } + export function createDiagnosticMessageChainFromDiagnostic(diagnostic: DiagnosticRelatedInformation): DiagnosticMessageChain { + return typeof diagnostic.messageText === "string" ? { + code: diagnostic.code, + category: diagnostic.category, + messageText: diagnostic.messageText, + next: (diagnostic as DiagnosticMessageChain).next, + } : diagnostic.messageText; + } + export function createDiagnosticForRange(sourceFile: SourceFile, range: TextRange, message: DiagnosticMessage): DiagnosticWithLocation { return { file: sourceFile, diff --git a/tests/baselines/reference/tsc/incremental/initial-build/serializing-error-chains.js b/tests/baselines/reference/tsc/incremental/initial-build/serializing-error-chains.js new file mode 100644 index 0000000000000..6cf4aaf5a3c1f --- /dev/null +++ b/tests/baselines/reference/tsc/incremental/initial-build/serializing-error-chains.js @@ -0,0 +1,185 @@ +Input:: +//// [/lib/lib.d.ts] +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } +interface ReadonlyArray {} +declare const console: { log(msg: any): void; }; +interface ReadonlyArray { readonly length: number } + +//// [/src/project/index.tsx] +declare namespace JSX { + interface ElementChildrenAttribute { children: {}; } + interface IntrinsicElements { div: {} } +} + +declare var React: any; + +declare function Component(props: never): any; +declare function Component(props: { children?: number }): any; +( +
+
+) + +//// [/src/project/tsconfig.json] +{"compilerOptions":{"incremental":true,"strict":true,"jsx":"react","module":"esnext"}} + + + +Output:: +/lib/tsc -p src/project +src/project/index.tsx:10:3 - error TS2746: This JSX tag's 'children' prop expects a single child of type 'never', but multiple children were provided. + +10 ( +   ~~~~~~~~~ + +src/project/index.tsx:10:3 - error TS2746: This JSX tag's 'children' prop expects a single child of type 'number | undefined', but multiple children were provided. + +10 ( +   ~~~~~~~~~ + +src/project/index.tsx:10:3 - error TS2769: No overload matches this call. + This JSX tag's 'children' prop expects a single child of type 'never', but multiple children were provided. + This JSX tag's 'children' prop expects a single child of type 'number | undefined', but multiple children were provided. + +10 ( +   ~~~~~~~~~ + + + +Found 3 errors in the same file, starting at: src/project/index.tsx:10 + +exitCode:: ExitStatus.DiagnosticsPresent_OutputsGenerated + + +//// [/src/project/index.js] +"use strict"; +(React.createElement(Component, null, + React.createElement("div", null), + React.createElement("div", null))); + + +//// [/src/project/tsconfig.tsbuildinfo] +{"program":{"fileNames":["../../lib/lib.d.ts","./index.tsx"],"fileInfos":[{"version":"7198220534-/// \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; }\ninterface ReadonlyArray {}\ndeclare const console: { log(msg: any): void; };\ninterface ReadonlyArray { readonly length: number }","affectsGlobalScope":true},{"version":"42569361247-declare namespace JSX {\n interface ElementChildrenAttribute { children: {}; }\n interface IntrinsicElements { div: {} }\n}\n\ndeclare var React: any;\n\ndeclare function Component(props: never): any;\ndeclare function Component(props: { children?: number }): any;\n(\n
\n
\n)","affectsGlobalScope":true}],"options":{"jsx":2,"module":99,"strict":true},"referencedMap":[],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[1,[2,[{"file":"./index.tsx","start":265,"length":9,"messageText":"This JSX tag's 'children' prop expects a single child of type 'never', but multiple children were provided.","category":1,"code":2746},{"file":"./index.tsx","start":265,"length":9,"messageText":"This JSX tag's 'children' prop expects a single child of type 'number | undefined', but multiple children were provided.","category":1,"code":2746},{"file":"./index.tsx","start":265,"length":9,"code":2769,"category":1,"messageText":{"messageText":"No overload matches this call.","category":1,"code":2769,"next":[{"code":2746,"category":1,"messageText":"This JSX tag's 'children' prop expects a single child of type 'never', but multiple children were provided."},{"code":2746,"category":1,"messageText":"This JSX tag's 'children' prop expects a single child of type 'number | undefined', but multiple children were provided."}]},"relatedInformation":[]}]]]},"version":"FakeTSVersion"} + +//// [/src/project/tsconfig.tsbuildinfo.readable.baseline.txt] +{ + "program": { + "fileNames": [ + "../../lib/lib.d.ts", + "./index.tsx" + ], + "fileInfos": { + "../../lib/lib.d.ts": { + "version": "7198220534-/// \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; }\ninterface ReadonlyArray {}\ndeclare const console: { log(msg: any): void; };\ninterface ReadonlyArray { readonly length: number }", + "signature": "7198220534-/// \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; }\ninterface ReadonlyArray {}\ndeclare const console: { log(msg: any): void; };\ninterface ReadonlyArray { readonly length: number }", + "affectsGlobalScope": true + }, + "./index.tsx": { + "version": "42569361247-declare namespace JSX {\n interface ElementChildrenAttribute { children: {}; }\n interface IntrinsicElements { div: {} }\n}\n\ndeclare var React: any;\n\ndeclare function Component(props: never): any;\ndeclare function Component(props: { children?: number }): any;\n(\n
\n
\n)", + "signature": "42569361247-declare namespace JSX {\n interface ElementChildrenAttribute { children: {}; }\n interface IntrinsicElements { div: {} }\n}\n\ndeclare var React: any;\n\ndeclare function Component(props: never): any;\ndeclare function Component(props: { children?: number }): any;\n(\n
\n
\n)", + "affectsGlobalScope": true + } + }, + "options": { + "jsx": 2, + "module": 99, + "strict": true + }, + "referencedMap": {}, + "exportedModulesMap": {}, + "semanticDiagnosticsPerFile": [ + "../../lib/lib.d.ts", + [ + "./index.tsx", + [ + { + "file": "./index.tsx", + "start": 265, + "length": 9, + "messageText": "This JSX tag's 'children' prop expects a single child of type 'never', but multiple children were provided.", + "category": 1, + "code": 2746 + }, + { + "file": "./index.tsx", + "start": 265, + "length": 9, + "messageText": "This JSX tag's 'children' prop expects a single child of type 'number | undefined', but multiple children were provided.", + "category": 1, + "code": 2746 + }, + { + "file": "./index.tsx", + "start": 265, + "length": 9, + "code": 2769, + "category": 1, + "messageText": { + "messageText": "No overload matches this call.", + "category": 1, + "code": 2769, + "next": [ + { + "code": 2746, + "category": 1, + "messageText": "This JSX tag's 'children' prop expects a single child of type 'never', but multiple children were provided." + }, + { + "code": 2746, + "category": 1, + "messageText": "This JSX tag's 'children' prop expects a single child of type 'number | undefined', but multiple children were provided." + } + ] + }, + "relatedInformation": [] + } + ] + ] + ] + }, + "version": "FakeTSVersion", + "size": 2053 +} + + + +Change:: no-change-run +Input:: + + +Output:: +/lib/tsc -p src/project +src/project/index.tsx:10:3 - error TS2746: This JSX tag's 'children' prop expects a single child of type 'never', but multiple children were provided. + +10 ( +   ~~~~~~~~~ + +src/project/index.tsx:10:3 - error TS2746: This JSX tag's 'children' prop expects a single child of type 'number | undefined', but multiple children were provided. + +10 ( +   ~~~~~~~~~ + +src/project/index.tsx:10:3 - error TS2769: No overload matches this call. + This JSX tag's 'children' prop expects a single child of type 'never', but multiple children were provided. + This JSX tag's 'children' prop expects a single child of type 'number | undefined', but multiple children were provided. + +10 ( +   ~~~~~~~~~ + + + +Found 3 errors in the same file, starting at: src/project/index.tsx:10 + +exitCode:: ExitStatus.DiagnosticsPresent_OutputsGenerated + +