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

During uptodate ness check with buildInfo, check if there are errors explicitly with noEmit #50974

Merged
merged 3 commits into from Sep 27, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/compiler/tsbuildPublic.ts
Expand Up @@ -1609,8 +1609,14 @@ namespace ts {

if (buildInfo.program) {
// If there are pending changes that are not emitted, project is out of date
// If noEmit, then explicitly check if there are semantic diagnostics
// affectedFilesPendingEmit is present in noEmit irrespective of errors to handle files to be emitted when noEmit is false,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helps me understand why affectedFilesPendingEmit behaves differently under noEmit, but I don’t understand why that makes checking for the presence of semantic errors the correct fallback. Why does the presence of semantic errors definitely mean the buildinfo is out of date? Why isn’t the same true of syntactic errors?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If program has syntactic errors the changeFileSet because semantic diagnostics are not even processed in that case and state remains same. (https://github.com/microsoft/TypeScript/pull/50974/files#diff-2461280d51916bf4023650d8950c0af3bf16011e3f0c8a290c7c9f70056147a0R77) I will update the comment

//so explicit check on errors is needed in noEmit as oppose to when it is false when only files pending emit is sufficient
if ((buildInfo.program as ProgramMultiFileEmitBuildInfo).changeFileSet?.length ||
(!project.options.noEmit && (buildInfo.program as ProgramMultiFileEmitBuildInfo).affectedFilesPendingEmit?.length)) {
(!project.options.noEmit ?
(buildInfo.program as ProgramMultiFileEmitBuildInfo).affectedFilesPendingEmit?.length :
some((buildInfo.program as ProgramMultiFileEmitBuildInfo).semanticDiagnosticsPerFile, isArray))
) {
return {
type: UpToDateStatusType.OutOfDateBuildInfo,
buildInfoFile: buildInfoPath
Expand Down
1 change: 1 addition & 0 deletions src/testRunner/tsconfig.json
Expand Up @@ -132,6 +132,7 @@
"unittests/tsbuild/lateBoundSymbol.ts",
"unittests/tsbuild/moduleResolution.ts",
"unittests/tsbuild/moduleSpecifiers.ts",
"unittests/tsbuild/noEmit.ts",
"unittests/tsbuild/noEmitOnError.ts",
"unittests/tsbuild/outFile.ts",
"unittests/tsbuild/outputPaths.ts",
Expand Down
34 changes: 34 additions & 0 deletions src/testRunner/unittests/tsbuild/noEmit.ts
@@ -0,0 +1,34 @@
namespace ts {
describe("unittests:: tsbuild:: noEmit", () => {
function verifyNoEmitWorker(subScenario: string, aTsContent: string, commandLineArgs: readonly string[]) {
verifyTscWithEdits({
scenario: "noEmit",
subScenario,
fs: () => loadProjectFromFiles({
"/src/a.ts": aTsContent,
"/src/tsconfig.json": JSON.stringify({
compilerOptions: { noEmit: true }
})
}),
commandLineArgs,
edits: [
noChangeRun,
{
subScenario: "Fix error",
modifyFs: fs => fs.writeFileSync("/src/a.ts", `const a = "hello"`),
},
noChangeRun,
],
baselinePrograms: true,
});
}

function verifyNoEmit(subScenario: string, aTsContent: string) {
verifyNoEmitWorker(subScenario, aTsContent, ["--b", "/src/tsconfig.json", "-v"]);
verifyNoEmitWorker(`${subScenario} with incremental`, aTsContent, ["--b", "/src/tsconfig.json", "-v", "--incremental"]);
}

verifyNoEmit("syntax errors", `const a = "hello`);
verifyNoEmit("semantic errors", `const a: number = "hello"`);
});
}
@@ -0,0 +1,234 @@
Input::
//// [/lib/lib.d.ts]
/// <reference no-default-lib="true"/>
interface Boolean {}
interface Function {}
interface CallableFunction {}
interface NewableFunction {}
interface IArguments {}
interface Number { toExponential: any; }
interface Object {}
interface RegExp {}
interface String { charAt: any; }
interface Array<T> { length: number; [n: number]: T; }
interface ReadonlyArray<T> {}
declare const console: { log(msg: any): void; };

//// [/src/a.ts]
const a: number = "hello"

//// [/src/tsconfig.json]
{"compilerOptions":{"noEmit":true}}



Output::
/lib/tsc --b /src/tsconfig.json -v --incremental
[12:00:08 AM] Projects in this build:
* src/tsconfig.json

[12:00:09 AM] Project 'src/tsconfig.json' is out of date because output file 'src/tsconfig.tsbuildinfo' does not exist

[12:00:10 AM] Building project '/src/tsconfig.json'...

src/a.ts:1:7 - error TS2322: Type 'string' is not assignable to type 'number'.

1 const a: number = "hello"
   ~


Found 1 error.

exitCode:: ExitStatus.DiagnosticsPresent_OutputsSkipped
Program root files: ["/src/a.ts"]
Program options: {"noEmit":true,"incremental":true,"configFilePath":"/src/tsconfig.json"}
Program structureReused: Not
Program files::
/lib/lib.d.ts
/src/a.ts

Semantic diagnostics in builder refreshed for::
/lib/lib.d.ts
/src/a.ts

Shape signatures in builder refreshed for::
/lib/lib.d.ts (used version)
/src/a.ts (used version)


//// [/src/tsconfig.tsbuildinfo]
{"program":{"fileNames":["../lib/lib.d.ts","./a.ts"],"fileInfos":[{"version":"3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true},{"version":"1311033573-const a: number = \"hello\"","affectsGlobalScope":true}],"referencedMap":[],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[1,[2,[{"file":"./a.ts","start":6,"length":1,"code":2322,"category":1,"messageText":"Type 'string' is not assignable to type 'number'."}]]],"affectedFilesPendingEmit":[[2,1]]},"version":"FakeTSVersion"}

//// [/src/tsconfig.tsbuildinfo.readable.baseline.txt]
{
"program": {
"fileNames": [
"../lib/lib.d.ts",
"./a.ts"
],
"fileInfos": {
"../lib/lib.d.ts": {
"version": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"signature": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"affectsGlobalScope": true
},
"./a.ts": {
"version": "1311033573-const a: number = \"hello\"",
"signature": "1311033573-const a: number = \"hello\"",
"affectsGlobalScope": true
}
},
"referencedMap": {},
"exportedModulesMap": {},
"semanticDiagnosticsPerFile": [
"../lib/lib.d.ts",
[
"./a.ts",
[
{
"file": "./a.ts",
"start": 6,
"length": 1,
"code": 2322,
"category": 1,
"messageText": "Type 'string' is not assignable to type 'number'."
}
]
]
],
"affectedFilesPendingEmit": [
[
"./a.ts",
"Full"
]
]
},
"version": "FakeTSVersion",
"size": 899
}



Change:: no-change-run
Input::


Output::
/lib/tsc --b /src/tsconfig.json -v --incremental
[12:00:14 AM] Projects in this build:
* src/tsconfig.json

[12:00:15 AM] Project 'src/tsconfig.json' is out of date because buildinfo file 'src/tsconfig.tsbuildinfo' indicates that some of the changes were not emitted

[12:00:16 AM] Building project '/src/tsconfig.json'...

src/a.ts:1:7 - error TS2322: Type 'string' is not assignable to type 'number'.

1 const a: number = "hello"
   ~


Found 1 error.

exitCode:: ExitStatus.DiagnosticsPresent_OutputsSkipped
Program root files: ["/src/a.ts"]
Program options: {"noEmit":true,"incremental":true,"configFilePath":"/src/tsconfig.json"}
Program structureReused: Not
Program files::
/lib/lib.d.ts
/src/a.ts

Semantic diagnostics in builder refreshed for::

No shapes updated in the builder::




Change:: Fix error
Input::
//// [/src/a.ts]
const a = "hello"



Output::
/lib/tsc --b /src/tsconfig.json -v --incremental
[12:00:18 AM] Projects in this build:
* src/tsconfig.json

[12:00:19 AM] Project 'src/tsconfig.json' is out of date because buildinfo file 'src/tsconfig.tsbuildinfo' indicates that some of the changes were not emitted

[12:00:20 AM] Building project '/src/tsconfig.json'...

exitCode:: ExitStatus.Success
Program root files: ["/src/a.ts"]
Program options: {"noEmit":true,"incremental":true,"configFilePath":"/src/tsconfig.json"}
Program structureReused: Not
Program files::
/lib/lib.d.ts
/src/a.ts

Semantic diagnostics in builder refreshed for::
/lib/lib.d.ts
/src/a.ts

Shape signatures in builder refreshed for::
/src/a.ts (computed .d.ts)


//// [/src/tsconfig.tsbuildinfo]
{"program":{"fileNames":["../lib/lib.d.ts","./a.ts"],"fileInfos":[{"version":"3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true},{"version":"4011451714-const a = \"hello\"","signature":"-4100694204-declare const a = \"hello\";\r\n","affectsGlobalScope":true}],"referencedMap":[],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[1,2],"affectedFilesPendingEmit":[[2,1]]},"version":"FakeTSVersion"}

//// [/src/tsconfig.tsbuildinfo.readable.baseline.txt]
{
"program": {
"fileNames": [
"../lib/lib.d.ts",
"./a.ts"
],
"fileInfos": {
"../lib/lib.d.ts": {
"version": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"signature": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"affectsGlobalScope": true
},
"./a.ts": {
"version": "4011451714-const a = \"hello\"",
"signature": "-4100694204-declare const a = \"hello\";\r\n",
"affectsGlobalScope": true
}
},
"referencedMap": {},
"exportedModulesMap": {},
"semanticDiagnosticsPerFile": [
"../lib/lib.d.ts",
"./a.ts"
],
"affectedFilesPendingEmit": [
[
"./a.ts",
"Full"
]
]
},
"version": "FakeTSVersion",
"size": 816
}



Change:: no-change-run
Input::


Output::
/lib/tsc --b /src/tsconfig.json -v --incremental
[12:00:24 AM] Projects in this build:
* src/tsconfig.json

[12:00:25 AM] Project 'src/tsconfig.json' is up to date because newest input 'src/a.ts' is older than output 'src/tsconfig.tsbuildinfo'

exitCode:: ExitStatus.Success