diff --git a/.gitignore b/.gitignore index 9d0bb4d0c6f..04c397bb7e3 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ scripts/ior.js scripts/authors.js scripts/configurePrerelease.js scripts/open-user-pr.js +scripts/open-cherry-pick-pr.js scripts/processDiagnosticMessages.d.ts scripts/processDiagnosticMessages.js scripts/produceLKG.js diff --git a/package.json b/package.json index a50a79aff13..965c0c3bb32 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "typescript", "author": "Microsoft Corp.", "homepage": "https://www.typescriptlang.org/", - "version": "3.5.0", + "version": "3.6.0", "license": "Apache-2.0", "description": "TypeScript is a language for application scale JavaScript development", "keywords": [ @@ -48,11 +48,13 @@ "@types/mocha": "latest", "@types/ms": "latest", "@types/node": "8.5.5", + "@types/node-fetch": "^2.3.4", "@types/q": "latest", "@types/source-map-support": "latest", "@types/through2": "latest", "@types/travis-fold": "latest", "@types/xml2js": "^0.4.0", + "azure-devops-node-api": "^8.0.0", "browser-resolve": "^1.11.2", "browserify": "latest", "chai": "latest", @@ -74,6 +76,7 @@ "mocha": "latest", "mocha-fivemat-progress-reporter": "latest", "ms": "latest", + "node-fetch": "^2.6.0", "plugin-error": "latest", "pretty-hrtime": "^1.0.3", "prex": "^0.4.3", diff --git a/scripts/open-cherry-pick-pr.ts b/scripts/open-cherry-pick-pr.ts new file mode 100644 index 00000000000..8bdeb05e4a2 --- /dev/null +++ b/scripts/open-cherry-pick-pr.ts @@ -0,0 +1,105 @@ +/// +// Must reference esnext.asynciterable lib, since octokit uses AsyncIterable internally +/// + +import Octokit = require("@octokit/rest"); +const {runSequence} = require("./run-sequence"); +import fs = require("fs"); +import path = require("path"); + +const userName = process.env.GH_USERNAME; +const reviewers = process.env.REQUESTING_USER ? [process.env.REQUESTING_USER] : ["weswigham", "RyanCavanaugh"]; +const branchName = `pick/${process.env.SOURCE_ISSUE}/${process.env.TARGET_BRANCH}`; +const remoteUrl = `https://${process.argv[2]}@github.com/${userName}/TypeScript.git`; + +async function main() { + if (!process.env.TARGET_BRANCH) { + throw new Error("Target branch not specified"); + } + if (!process.env.SOURCE_ISSUE) { + throw new Error("Source issue not specified"); + } + const currentSha = runSequence([ + ["git", ["rev-parse", "HEAD"]] + ]); + const currentAuthor = runSequence([ + ["git", ["log", "-1", `--pretty="%aN <%aE>"`]] + ]); + runSequence([ + ["git", ["fetch", "origin", "master"]] + ]); + let logText = runSequence([ + ["git", ["log", `origin/master..${currentSha.trim()}`, `--pretty="%h %s%n%b"`, "--reverse"]] + ]); + logText = `Cherry-pick PR #${process.env.SOURCE_ISSUE} into ${process.env.TARGET_BRANCH} + +Component commits: +${logText.trim()}` + const logpath = path.join(__dirname, "../", "logmessage.txt"); + runSequence([ + ["git", ["checkout", "-b", "temp-branch"]], + ["git", ["reset", "origin/master", "--soft"]] + ]); + fs.writeFileSync(logpath, logText); + runSequence([ + ["git", ["commit", "-F", logpath, `--author="${currentAuthor.trim()}"`]] + ]); + fs.unlinkSync(logpath); + const squashSha = runSequence([ + ["git", ["rev-parse", "HEAD"]] + ]); + runSequence([ + ["git", ["checkout", process.env.TARGET_BRANCH]], // checkout the target branch + ["git", ["checkout", "-b", branchName]], // create a new branch + ["git", ["cherry-pick", squashSha.trim()]], // + ["git", ["remote", "add", "fork", remoteUrl]], // Add the remote fork + ["git", ["push", "--set-upstream", "fork", branchName, "-f"]] // push the branch + ]); + + const gh = new Octokit(); + gh.authenticate({ + type: "token", + token: process.argv[2] + }); + const r = await gh.pulls.create({ + owner: "Microsoft", + repo: "TypeScript", + maintainer_can_modify: true, + title: `🤖 Cherry-pick PR #${process.env.SOURCE_ISSUE} into ${process.env.TARGET_BRANCH}`, + head: `${userName}:${branchName}`, + base: process.env.TARGET_BRANCH, + body: + `This cherry-pick was triggerd by a request on https://github.com/Microsoft/TypeScript/pull/${process.env.SOURCE_ISSUE} +Please review the diff and merge if no changes are unexpected. +You can view the cherry-pick log [here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary). + +cc ${reviewers.map(r => "@" + r).join(" ")}`, + }); + const num = r.data.number; + console.log(`Pull request ${num} created.`); + + await gh.issues.createComment({ + number: +process.env.SOURCE_ISSUE, + owner: "Microsoft", + repo: "TypeScript", + body: `Hey @${process.env.REQUESTING_USER}, I've opened #${num} for you.` + }); +} + +main().catch(async e => { + console.error(e); + process.exitCode = 1; + if (process.env.SOURCE_ISSUE) { + const gh = new Octokit(); + gh.authenticate({ + type: "token", + token: process.argv[2] + }); + await gh.issues.createComment({ + number: +process.env.SOURCE_ISSUE, + owner: "Microsoft", + repo: "TypeScript", + body: `Hey @${process.env.REQUESTING_USER}, I couldn't open a PR with the cherry-pick. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary)). You may need to squash and pick this PR into ${process.env.TARGET_BRANCH} manually.` + }); + } +}); \ No newline at end of file diff --git a/scripts/open-user-pr.ts b/scripts/open-user-pr.ts index 0a636c267b8..23e4bb951d7 100644 --- a/scripts/open-user-pr.ts +++ b/scripts/open-user-pr.ts @@ -9,7 +9,7 @@ function padNum(number: number) { } const userName = process.env.GH_USERNAME; -const reviewers = process.env.requesting_user ? [process.env.requesting_user] : ["weswigham", "sandersn", "RyanCavanaugh"]; +const reviewers = process.env.REQUESTING_USER ? [process.env.REQUESTING_USER] : ["weswigham", "sandersn", "RyanCavanaugh"]; const now = new Date(); const branchName = `user-update-${process.env.TARGET_FORK}-${now.getFullYear()}${padNum(now.getMonth())}${padNum(now.getDay())}${process.env.TARGET_BRANCH ? "-" + process.env.TARGET_BRANCH : ""}`; const remoteUrl = `https://${process.argv[2]}@github.com/${userName}/TypeScript.git`; @@ -36,14 +36,14 @@ gh.pulls.create({ head: `${userName}:${branchName}`, base: process.env.TARGET_BRANCH || "master", body: -`${process.env.source_issue ? `This test run was triggerd by a request on https://github.com/Microsoft/TypeScript/pull/${process.env.source_issue} `+"\n" : ""}Please review the diff and merge if no changes are unexpected. +`${process.env.SOURCE_ISSUE ? `This test run was triggerd by a request on https://github.com/Microsoft/TypeScript/pull/${process.env.SOURCE_ISSUE} `+"\n" : ""}Please review the diff and merge if no changes are unexpected. You can view the build log [here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary). cc ${reviewers.map(r => "@" + r).join(" ")}`, }).then(async r => { const num = r.data.number; console.log(`Pull request ${num} created.`); - if (!process.env.source_issue) { + if (!process.env.SOURCE_ISSUE) { await gh.pulls.createReviewRequest({ owner: process.env.TARGET_FORK, repo: "TypeScript", @@ -53,7 +53,7 @@ cc ${reviewers.map(r => "@" + r).join(" ")}`, } else { await gh.issues.createComment({ - number: +process.env.source_issue, + number: +process.env.SOURCE_ISSUE, owner: "Microsoft", repo: "TypeScript", body: `The user suite test run you requested has finished and _failed_. I've opened a [PR with the baseline diff from master](${r.data.html_url}).` diff --git a/scripts/post-vsts-artifact-comment.js b/scripts/post-vsts-artifact-comment.js new file mode 100644 index 00000000000..6d84294bcfe --- /dev/null +++ b/scripts/post-vsts-artifact-comment.js @@ -0,0 +1,64 @@ +// @ts-check +/// +// Must reference esnext.asynciterable lib, since octokit uses AsyncIterable internally +const Octokit = require("@octokit/rest"); +const ado = require("azure-devops-node-api"); +const { default: fetch } = require("node-fetch"); + +async function main() { + if (!process.env.SOURCE_ISSUE) { + throw new Error("No source issue specified"); + } + if (!process.env.BUILD_BUILDID) { + throw new Error("No build ID specified"); + } + // The pipelines API does _not_ make getting the direct URL to a specific file _within_ an artifact trivial + const cli = new ado.WebApi("https://typescript.visualstudio.com/defaultcollection", ado.getHandlerFromToken("")); // Empty token, anon auth + const build = await cli.getBuildApi(); + const artifact = await build.getArtifact("typescript", +process.env.BUILD_BUILDID, "tgz"); + const updatedUrl = new URL(artifact.resource.url); + updatedUrl.search = `artifactName=tgz&fileId=${artifact.resource.data}&fileName=manifest`; + const resp = await (await fetch(`${updatedUrl}`)).json(); + const file = resp.items[0]; + const tgzUrl = new URL(artifact.resource.url); + tgzUrl.search = `artifactName=tgz&fileId=${file.blob.id}&fileName=${file.path}`; + const link = "" + tgzUrl; + const gh = new Octokit(); + gh.authenticate({ + type: "token", + token: process.argv[2] + }); + await gh.issues.createComment({ + number: +process.env.SOURCE_ISSUE, + owner: "Microsoft", + repo: "TypeScript", + body: `Hey @${process.env.REQUESTING_USER}, I've packed this into [an installable tgz](${link}). You can install it for testing by referencing it in your \`package.json\` like so: +\`\`\` +{ + "devDependencies": { + "typescript": "${link}" + } +} +\`\`\` +and then running \`npm install\`. +` + }); +} + +main().catch(async e => { + console.error(e); + process.exitCode = 1; + if (process.env.SOURCE_ISSUE) { + const gh = new Octokit(); + gh.authenticate({ + type: "token", + token: process.argv[2] + }); + await gh.issues.createComment({ + number: +process.env.SOURCE_ISSUE, + owner: "Microsoft", + repo: "TypeScript", + body: `Hey @${process.env.REQUESTING_USER}, something went wrong when looking for the build artifact. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary)).` + }); + } +}); \ No newline at end of file diff --git a/scripts/run-sequence.js b/scripts/run-sequence.js index ef7a384af4c..f014cde1b91 100644 --- a/scripts/run-sequence.js +++ b/scripts/run-sequence.js @@ -5,12 +5,13 @@ const cp = require("child_process"); * @param {[string, string[]][]} tasks * @param {cp.SpawnSyncOptions} opts */ -function runSequence(tasks, opts = { timeout: 100000, shell: true, stdio: "inherit" }) { +function runSequence(tasks, opts = { timeout: 100000, shell: true }) { let lastResult; for (const task of tasks) { console.log(`${task[0]} ${task[1].join(" ")}`); const result = cp.spawnSync(task[0], task[1], opts); if (result.status !== 0) throw new Error(`${task[0]} ${task[1].join(" ")} failed: ${result.stderr && result.stderr.toString()}`); + console.log(result.stdout && result.stdout.toString()); lastResult = result; } return lastResult && lastResult.stdout && lastResult.stdout.toString(); diff --git a/scripts/update-experimental-branches.js b/scripts/update-experimental-branches.js index c112cf1a367..b734c8a6fd8 100644 --- a/scripts/update-experimental-branches.js +++ b/scripts/update-experimental-branches.js @@ -1,87 +1,91 @@ // @ts-check /// const Octokit = require("@octokit/rest"); -const {runSequence} = require("./run-sequence"); +const { runSequence } = require("./run-sequence"); + +// The first is used by bot-based kickoffs, the second by automatic triggers +const triggeredPR = process.env.SOURCE_ISSUE || process.env.SYSTEM_PULLREQUEST_PULLREQUESTNUMBER; /** - * This program should be invoked as `node ./scripts/update-experimental-branches [Branch2] [...]` + * This program should be invoked as `node ./scripts/update-experimental-branches [PR2] [...]` + * The order PR numbers are passed controls the order in which they are merged together. + * TODO: the following is racey - if two experiment-enlisted PRs trigger simultaneously and witness one another in an unupdated state, they'll both produce + * a new experimental branch, but each will be missing a change from the other. There's no _great_ way to fix this beyond setting the maximum concurrency + * of this task to 1 (so only one job is allowed to update experiments at a time). */ async function main() { - const branchesRaw = process.argv[3]; - const branches = process.argv.slice(3); - if (!branches.length) { - throw new Error(`No experimental branches, aborting...`); + const prnums = process.argv.slice(3); + if (!prnums.length) { + return; // No enlisted PRs, nothing to update } - console.log(`Performing experimental branch updating and merging for branches ${branchesRaw}`); + if (!prnums.some(n => n === triggeredPR)) { + return; // Only have work to do for enlisted PRs + } + console.log(`Performing experimental branch updating and merging for pull requests ${prnums.join(", ")}`); + + const userName = process.env.GH_USERNAME; + const remoteUrl = `https://${process.argv[2]}@github.com/${userName}/TypeScript.git`; - const gh = new Octokit(); - gh.authenticate({ - type: "token", - token: process.argv[2] - }); - - // Fetch all relevant refs - runSequence([ - ["git", ["fetch", "origin", "master:master", ...branches.map(b => `${b}:${b}`)]] - ]) - // Forcibly cleanup workspace runSequence([ - ["git", ["clean", "-fdx"]], ["git", ["checkout", "."]], + ["git", ["fetch", "-fu", "origin", "master:master"]], ["git", ["checkout", "master"]], + ["git", ["remote", "add", "fork", remoteUrl]], // Add the remote fork ]); - - // Update branches - for (const branch of branches) { - // Checkout, then get the merge base - const mergeBase = runSequence([ - ["git", ["checkout", branch]], - ["git", ["merge-base", branch, "master"]], - ]); - // Simulate the merge and abort if there are conflicts - const mergeTree = runSequence([ - ["git", ["merge-tree", mergeBase, branch, "master"]] - ]); - if (mergeTree.indexOf(`===${"="}===`)) { // 7 equals is the center of the merge conflict marker - const res = await gh.pulls.list({owner: "Microsoft", repo: "TypeScript", base: branch}); - if (res && res.data && res.data[0]) { - const pr = res.data[0]; - await gh.issues.createComment({ - owner: "Microsoft", - repo: "TypeScript", - number: pr.number, - body: `This PR is configured as an experiment, and currently has merge conflicts with master - please rebase onto master and fix the conflicts.` - }); + + const gh = new Octokit({ + auth: process.argv[2] + }); + for (const numRaw of prnums) { + const num = +numRaw; + if (num) { + // PR number rather than branch name - lookup info + const inputPR = await gh.pulls.get({ owner: "Microsoft", repo: "TypeScript", pull_number: num }); + // GH calculates the rebaseable-ness of a PR into its target, so we can just use that here + if (!inputPR.data.rebaseable) { + if (+triggeredPR === num) { + await gh.issues.createComment({ + owner: "Microsoft", + repo: "TypeScript", + issue_number: num, + body: `This PR is configured as an experiment, and currently has rebase conflicts with master - please rebase onto master and fix the conflicts.` + }); + throw new Error(`Rebase conflict detected in PR ${num} with master`); + } + return; // A PR is currently in conflict, give up } - throw new Error(`Merge conflict detected on branch ${branch} with master`); + runSequence([ + ["git", ["fetch", "origin", `pull/${num}/head:${num}`]], + ["git", ["checkout", `${num}`]], + ["git", ["rebase", "master"]], + ["git", ["push", "-f", "-u", "fork", `${num}`]], // Keep a rebased copy of this branch in our fork + ]); + + } + else { + throw new Error(`Invalid PR number: ${numRaw}`); } - // Merge is good - apply a rebase and (force) push - runSequence([ - ["git", ["rebase", "master"]], - ["git", ["push", "-f", "-u", "origin", branch]], - ]); } // Return to `master` and make a new `experimental` branch runSequence([ ["git", ["checkout", "master"]], - ["git", ["branch", "-D", "experimental"]], ["git", ["checkout", "-b", "experimental"]], ]); // Merge each branch into `experimental` (which, if there is a conflict, we now know is from inter-experiment conflict) - for (const branch of branches) { + for (const branch of prnums) { // Find the merge base const mergeBase = runSequence([ ["git", ["merge-base", branch, "experimental"]], ]); // Simulate the merge and abort if there are conflicts const mergeTree = runSequence([ - ["git", ["merge-tree", mergeBase, branch, "experimental"]] + ["git", ["merge-tree", mergeBase.trim(), branch, "experimental"]] ]); - if (mergeTree.indexOf(`===${"="}===`)) { // 7 equals is the center of the merge conflict marker - throw new Error(`Merge conflict detected on branch ${branch} with other experiment`); + if (mergeTree.indexOf(`===${"="}===`) >= 0) { // 7 equals is the center of the merge conflict marker + throw new Error(`Merge conflict detected involving PR ${branch} with other experiment`); } // Merge (always producing a merge commit) runSequence([ @@ -90,7 +94,7 @@ async function main() { } // Every branch merged OK, force push the replacement `experimental` branch runSequence([ - ["git", ["push", "-f", "-u", "origin", "experimental"]], + ["git", ["push", "-f", "-u", "fork", "experimental"]], ]); } diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 4540a4409d6..660b19a5872 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3229,8 +3229,7 @@ namespace ts { // A ClassDeclaration is ES6 syntax. transformFlags = subtreeFlags | TransformFlags.AssertES2015; - // A class with a parameter property assignment, property initializer, computed property name, or decorator is - // TypeScript syntax. + // A class with a parameter property assignment or decorator is TypeScript syntax. // An exported declaration may be TypeScript syntax, but is handled by the visitor // for a namespace declaration. if ((subtreeFlags & TransformFlags.ContainsTypeScriptClassSyntax) @@ -3247,8 +3246,7 @@ namespace ts { // A ClassExpression is ES6 syntax. let transformFlags = subtreeFlags | TransformFlags.AssertES2015; - // A class with a parameter property assignment, property initializer, or decorator is - // TypeScript syntax. + // A class with a parameter property assignment or decorator is TypeScript syntax. if (subtreeFlags & TransformFlags.ContainsTypeScriptClassSyntax || node.typeParameters) { transformFlags |= TransformFlags.AssertTypeScript; @@ -3338,7 +3336,6 @@ namespace ts { || hasModifier(node, ModifierFlags.TypeScriptModifier) || node.typeParameters || node.type - || (node.name && isComputedPropertyName(node.name)) // While computed method names aren't typescript, the TS transform must visit them to emit property declarations correctly || !node.body) { transformFlags |= TransformFlags.AssertTypeScript; } @@ -3369,7 +3366,6 @@ namespace ts { if (node.decorators || hasModifier(node, ModifierFlags.TypeScriptModifier) || node.type - || (node.name && isComputedPropertyName(node.name)) // While computed accessor names aren't typescript, the TS transform must visit them to emit property declarations correctly || !node.body) { transformFlags |= TransformFlags.AssertTypeScript; } @@ -3384,12 +3380,15 @@ namespace ts { } function computePropertyDeclaration(node: PropertyDeclaration, subtreeFlags: TransformFlags) { - // A PropertyDeclaration is TypeScript syntax. - let transformFlags = subtreeFlags | TransformFlags.AssertTypeScript; + let transformFlags = subtreeFlags | TransformFlags.ContainsClassFields; - // If the PropertyDeclaration has an initializer or a computed name, we need to inform its ancestor - // so that it handle the transformation. - if (node.initializer || isComputedPropertyName(node.name)) { + // Decorators, TypeScript-specific modifiers, and type annotations are TypeScript syntax. + if (some(node.decorators) || hasModifier(node, ModifierFlags.TypeScriptModifier) || node.type) { + transformFlags |= TransformFlags.AssertTypeScript; + } + + // Hoisted variables related to class properties should live within the TypeScript class wrapper. + if (isComputedPropertyName(node.name) || (hasStaticModifier(node) && node.initializer)) { transformFlags |= TransformFlags.ContainsTypeScriptClassSyntax; } diff --git a/src/compiler/builder.ts b/src/compiler/builder.ts index 78058bf5a53..d4c2132d36b 100644 --- a/src/compiler/builder.ts +++ b/src/compiler/builder.ts @@ -796,6 +796,7 @@ namespace ts { (result as SemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile = getSemanticDiagnosticsOfNextAffectedFile; } else if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) { + (result as EmitAndSemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile = getSemanticDiagnosticsOfNextAffectedFile; (result as EmitAndSemanticDiagnosticsBuilderProgram).emitNextAffectedFile = emitNextAffectedFile; } else { @@ -913,6 +914,11 @@ namespace ts { ); } + // Add file to affected file pending emit to handle for later emit time + if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) { + addToAffectedFilesPendingEmit(state, [(affected as SourceFile).path]); + } + // Get diagnostics for the affected file if its not ignored if (ignoreSourceFile && ignoreSourceFile(affected as SourceFile)) { // Get next affected file @@ -951,18 +957,8 @@ namespace ts { // When semantic builder asks for diagnostics of the whole program, // ensure that all the affected files are handled - let affected: SourceFile | Program | undefined; - let affectedFilesPendingEmit: Path[] | undefined; - while (affected = getNextAffectedFile(state, cancellationToken, computeHash)) { - if (affected !== state.program && kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) { - (affectedFilesPendingEmit || (affectedFilesPendingEmit = [])).push((affected as SourceFile).path); - } - doneWithAffectedFile(state, affected); - } - - // In case of emit builder, cache the files to be emitted - if (affectedFilesPendingEmit) { - addToAffectedFilesPendingEmit(state, affectedFilesPendingEmit); + // tslint:disable-next-line no-empty + while (getSemanticDiagnosticsOfNextAffectedFile(cancellationToken)) { } let diagnostics: Diagnostic[] | undefined; @@ -997,7 +993,7 @@ namespace ts { return map; } - export function createBuildProgramUsingProgramBuildInfo(program: ProgramBuildInfo): EmitAndSemanticDiagnosticsBuilderProgram & SemanticDiagnosticsBuilderProgram { + export function createBuildProgramUsingProgramBuildInfo(program: ProgramBuildInfo): EmitAndSemanticDiagnosticsBuilderProgram { const fileInfos = createMapFromTemplate(program.fileInfos); const state: ReusableBuilderProgramState = { fileInfos, @@ -1181,7 +1177,7 @@ namespace ts { * The builder that can handle the changes in program and iterate through changed file to emit the files * The semantic diagnostics are cached per file and managed by clearing for the changed/affected files */ - export interface EmitAndSemanticDiagnosticsBuilderProgram extends BuilderProgram { + export interface EmitAndSemanticDiagnosticsBuilderProgram extends SemanticDiagnosticsBuilderProgram { /** * Emits the next affected file's emit result (EmitResult and sourceFiles emitted) or returns undefined if iteration is complete * The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c221da7bdb2..817364ba832 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -182,6 +182,10 @@ namespace ts { node = getParseTreeNode(node); return node ? getTypeOfNode(node) : errorType; }, + getTypeOfAssignmentPattern: nodeIn => { + const node = getParseTreeNode(nodeIn, isAssignmentPattern); + return node && getTypeOfAssignmentPattern(node) || errorType; + }, getPropertySymbolOfDestructuringAssignment: locationIn => { const location = getParseTreeNode(locationIn, isIdentifier); return location ? getPropertySymbolOfDestructuringAssignment(location) : undefined; @@ -5227,7 +5231,7 @@ namespace ts { } } // Use contextual parameter type if one is available - const type = declaration.symbol.escapedName === InternalSymbolName.This ? getContextualThisParameterType(func) : getContextuallyTypedParameterType(declaration); + const type = declaration.symbol.escapedName === InternalSymbolName.This ? getContextualThisParameterType(func) : getContextuallyTypedParameterType(declaration, /*forCache*/ true); if (type) { return addOptionality(type, isOptional); } @@ -5917,7 +5921,20 @@ namespace ts { return anyType; } + function getTypeOfSymbolWithDeferredType(symbol: Symbol) { + const links = getSymbolLinks(symbol); + if (!links.type) { + Debug.assertDefined(links.deferralParent); + Debug.assertDefined(links.deferralConstituents); + links.type = links.deferralParent!.flags & TypeFlags.Union ? getUnionType(links.deferralConstituents!) : getIntersectionType(links.deferralConstituents!); + } + return links.type; + } + function getTypeOfSymbol(symbol: Symbol): Type { + if (getCheckFlags(symbol) & CheckFlags.DeferredType) { + return getTypeOfSymbolWithDeferredType(symbol); + } if (getCheckFlags(symbol) & CheckFlags.Instantiated) { return getTypeOfInstantiatedSymbol(symbol); } @@ -7052,10 +7069,10 @@ namespace ts { // Union the result types when more than one signature matches if (unionSignatures.length > 1) { let thisParameter = signature.thisParameter; - if (forEach(unionSignatures, sig => sig.thisParameter)) { - // TODO: GH#18217 We tested that *some* has thisParameter and now act as if *all* do + const firstThisParameterOfUnionSignatures = forEach(unionSignatures, sig => sig.thisParameter); + if (firstThisParameterOfUnionSignatures) { const thisType = getUnionType(map(unionSignatures, sig => sig.thisParameter ? getTypeOfSymbol(sig.thisParameter) : anyType), UnionReduction.Subtype); - thisParameter = createSymbolWithType(signature.thisParameter!, thisType); + thisParameter = createSymbolWithType(firstThisParameterOfUnionSignatures, thisType); } s = createUnionSignature(signature, unionSignatures); s.thisParameter = thisParameter; @@ -7299,7 +7316,8 @@ namespace ts { stringIndexInfo = createIndexInfo(anyType, /*isReadonly*/ false); } } - const numberIndexInfo = symbol.flags & SymbolFlags.Enum ? enumNumberIndexInfo : undefined; + const numberIndexInfo = symbol.flags & SymbolFlags.Enum && (getDeclaredTypeOfSymbol(symbol).flags & TypeFlags.Enum || + some(type.properties, prop => !!(getTypeOfSymbol(prop).flags & TypeFlags.NumberLike))) ? enumNumberIndexInfo : undefined; setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); // We resolve the members before computing the signatures because a signature may use // typeof with a qualified name expression that circularly references the type we are @@ -7999,10 +8017,13 @@ namespace ts { else if (isUnion) { const indexInfo = !isLateBoundName(name) && (isNumericLiteralName(name) && getIndexInfoOfType(type, IndexKind.Number) || getIndexInfoOfType(type, IndexKind.String)); if (indexInfo) { - checkFlags |= indexInfo.isReadonly ? CheckFlags.Readonly : 0; - checkFlags |= CheckFlags.WritePartial; + checkFlags |= CheckFlags.WritePartial | (indexInfo.isReadonly ? CheckFlags.Readonly : 0); indexTypes = append(indexTypes, isTupleType(type) ? getRestTypeOfTupleType(type) || undefinedType : indexInfo.type); } + else if (isObjectLiteralType(type)) { + checkFlags |= CheckFlags.WritePartial; + indexTypes = append(indexTypes, undefinedType); + } else { checkFlags |= CheckFlags.ReadPartial; } @@ -8057,7 +8078,15 @@ namespace ts { result.declarations = declarations!; result.nameType = nameType; - result.type = isUnion ? getUnionType(propTypes) : getIntersectionType(propTypes); + if (propTypes.length > 2) { + // When `propTypes` has the potential to explode in size when normalized, defer normalization until absolutely needed + result.checkFlags |= CheckFlags.DeferredType; + result.deferralParent = containingType; + result.deferralConstituents = propTypes; + } + else { + result.type = isUnion ? getUnionType(propTypes) : getIntersectionType(propTypes); + } return result; } @@ -8166,6 +8195,9 @@ namespace ts { propTypes.push(getTypeOfSymbol(prop)); } } + if (kind === IndexKind.String) { + append(propTypes, getIndexTypeOfType(type, IndexKind.Number)); + } if (propTypes.length) { return getUnionType(propTypes, UnionReduction.Subtype); } @@ -9908,6 +9940,12 @@ namespace ts { else { // We are attempting to construct a type of the form X & (A | B) & Y. Transform this into a type of // the form X & A & Y | X & B & Y and recursively reduce until no union type constituents remain. + // If the estimated size of the resulting union type exceeds 100000 constituents, report an error. + const size = reduceLeft(typeSet, (n, t) => n * (t.flags & TypeFlags.Union ? (t).types.length : 1), 1); + if (size >= 100000) { + error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent); + return errorType; + } const unionIndex = findIndex(typeSet, t => (t.flags & TypeFlags.Union) !== 0); const unionType = typeSet[unionIndex]; result = getUnionType(map(unionType.types, t => getIntersectionType(replaceElement(typeSet, unionIndex, t))), @@ -10067,7 +10105,7 @@ namespace ts { return false; } - function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, accessFlags: AccessFlags) { + function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, fullIndexType: Type, suppressNoImplicitAnyError: boolean, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, accessFlags: AccessFlags) { const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined; const propName = isTypeUsableAsPropertyName(indexType) ? getPropertyNameFromType(indexType) : @@ -10141,7 +10179,7 @@ namespace ts { if (objectType.symbol === globalThisSymbol && propName !== undefined && globalThisSymbol.exports!.has(propName) && (globalThisSymbol.exports!.get(propName)!.flags & SymbolFlags.BlockScoped)) { error(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(propName), typeToString(objectType)); } - else if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors) { + else if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors && !suppressNoImplicitAnyError) { if (propName !== undefined && typeHasStaticProperty(propName, objectType)) { error(accessExpression, Diagnostics.Property_0_is_a_static_member_of_type_1, propName as string, typeToString(objectType)); } @@ -10161,7 +10199,29 @@ namespace ts { error(accessExpression, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature_Did_you_mean_to_call_1, typeToString(objectType), suggestion); } else { - error(accessExpression, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, typeToString(objectType)); + let errorInfo: DiagnosticMessageChain | undefined; + if (indexType.flags & TypeFlags.EnumLiteral) { + errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, "[" + typeToString(indexType) + "]", typeToString(objectType)); + } + else if (indexType.flags & TypeFlags.UniqueESSymbol) { + const symbolName = getFullyQualifiedName((indexType as UniqueESSymbolType).symbol, accessExpression); + errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, "[" + symbolName + "]", typeToString(objectType)); + } + else if (indexType.flags & TypeFlags.StringLiteral) { + errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType as StringLiteralType).value, typeToString(objectType)); + } + else if (indexType.flags & TypeFlags.NumberLiteral) { + errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType as NumberLiteralType).value, typeToString(objectType)); + } + else if (indexType.flags & (TypeFlags.Number | TypeFlags.String)) { + errorInfo = chainDiagnosticMessages(/* details */ undefined, Diagnostics.No_index_signature_with_a_parameter_of_type_0_was_found_on_type_1, typeToString(indexType), typeToString(objectType)); + } + + errorInfo = chainDiagnosticMessages( + errorInfo, + Diagnostics.Element_implicitly_has_an_any_type_because_expression_of_type_0_can_t_be_used_to_index_type_1, typeToString(fullIndexType), typeToString(objectType) + ); + diagnostics.add(createDiagnosticForNodeFromMessageChain(accessExpression, errorInfo)); } } } @@ -10360,7 +10420,7 @@ namespace ts { const propTypes: Type[] = []; let wasMissingProp = false; for (const t of (indexType).types) { - const propType = getPropertyTypeForIndexType(objectType, apparentObjectType, t, accessNode, accessFlags); + const propType = getPropertyTypeForIndexType(objectType, apparentObjectType, t, indexType, wasMissingProp, accessNode, accessFlags); if (propType) { propTypes.push(propType); } @@ -10378,7 +10438,7 @@ namespace ts { } return accessFlags & AccessFlags.Writing ? getIntersectionType(propTypes) : getUnionType(propTypes); } - return getPropertyTypeForIndexType(objectType, apparentObjectType, indexType, accessNode, accessFlags | AccessFlags.CacheSymbol); + return getPropertyTypeForIndexType(objectType, apparentObjectType, indexType, indexType, /* supressNoImplicitAnyError */ false, accessNode, accessFlags | AccessFlags.CacheSymbol); } function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) { @@ -11462,6 +11522,7 @@ namespace ts { case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: case SyntaxKind.MethodDeclaration: + case SyntaxKind.FunctionDeclaration: // Function declarations can have context when annotated with a jsdoc @type return isContextSensitiveFunctionLikeDeclaration(node); case SyntaxKind.ObjectLiteralExpression: return some((node).properties, isContextSensitive); @@ -11495,6 +11556,9 @@ namespace ts { } function isContextSensitiveFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean { + if (isFunctionDeclaration(node) && (!isInJSFile(node) || !getTypeForDeclarationFromJSDocComment(node))) { + return false; + } // Functions with type parameters are not context sensitive. if (node.typeParameters) { return false; @@ -12281,8 +12345,8 @@ namespace ts { return false; } - function isIgnoredJsxProperty(source: Type, sourceProp: Symbol, targetMemberType: Type | undefined) { - return getObjectFlags(source) & ObjectFlags.JsxAttributes && !(isUnhyphenatedJsxName(sourceProp.escapedName) || targetMemberType); + function isIgnoredJsxProperty(source: Type, sourceProp: Symbol) { + return getObjectFlags(source) & ObjectFlags.JsxAttributes && !isUnhyphenatedJsxName(sourceProp.escapedName); } /** @@ -12928,6 +12992,18 @@ namespace ts { return result; } + function propagateSidebandVarianceFlags(typeArguments: readonly Type[], variances: VarianceFlags[]) { + for (let i = 0; i < variances.length; i++) { + const v = variances[i]; + if (v & VarianceFlags.Unmeasurable) { + instantiateType(typeArguments[i], reportUnmeasurableMarkers); + } + if (v & VarianceFlags.Unreliable) { + instantiateType(typeArguments[i], reportUnreliableMarkers); + } + } + } + // Determine if possibly recursive types are related. First, check if the result is already available in the global cache. // Second, check if we have already started a comparison of the given two types in which case we assume the result to be true. // Third, check if both types are part of deeply nested chains of generic type instantiations and if so assume the types are @@ -12945,6 +13021,16 @@ namespace ts { // as a failure, and should be updated as a reported failure by the bottom of this function. } else { + if (outofbandVarianceMarkerHandler) { + // We're in the middle of variance checking - integrate any unmeasurable/unreliable flags from this cached component + if (source.flags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol && + source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol) { + propagateSidebandVarianceFlags(source.aliasTypeArguments, getAliasVariances(source.aliasSymbol)); + } + if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target && length((source).typeArguments)) { + propagateSidebandVarianceFlags((source).typeArguments!, getVariances((source).target)); + } + } return related === RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False; } } @@ -13463,6 +13549,49 @@ namespace ts { return result || properties; } + function isPropertySymbolTypeRelated(sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean): Ternary { + const targetIsOptional = strictNullChecks && !!(getCheckFlags(targetProp) & CheckFlags.Partial); + const source = getTypeOfSourceProperty(sourceProp); + if (getCheckFlags(targetProp) & CheckFlags.DeferredType && !getSymbolLinks(targetProp).type) { + // Rather than resolving (and normalizing) the type, relate constituent-by-constituent without performing normalization or seconadary passes + const links = getSymbolLinks(targetProp); + Debug.assertDefined(links.deferralParent); + Debug.assertDefined(links.deferralConstituents); + const unionParent = !!(links.deferralParent!.flags & TypeFlags.Union); + let result = unionParent ? Ternary.False : Ternary.True; + const targetTypes = links.deferralConstituents!; + for (const targetType of targetTypes) { + const related = isRelatedTo(source, targetType, /*reportErrors*/ false, /*headMessage*/ undefined, /*isIntersectionConstituent*/ !unionParent); + if (!unionParent) { + if (!related) { + // Can't assign to a target individually - have to fallback to assigning to the _whole_ intersection (which forces normalization) + return isRelatedTo(source, addOptionality(getTypeOfSymbol(targetProp), targetIsOptional), reportErrors); + } + result &= related; + } + else { + if (related) { + return related; + } + } + } + if (unionParent && !result && targetIsOptional) { + result = isRelatedTo(source, undefinedType); + } + if (unionParent && !result && reportErrors) { + // The easiest way to get the right errors here is to un-defer (which may be costly) + // If it turns out this is too costly too often, we can replicate the error handling logic within + // typeRelatedToSomeType without the discriminatable type branch (as that requires a manifest union + // type on which to hand discriminable properties, which we are expressly trying to avoid here) + return isRelatedTo(source, addOptionality(getTypeOfSymbol(targetProp), targetIsOptional), reportErrors); + } + return result; + } + else { + return isRelatedTo(source, addOptionality(getTypeOfSymbol(targetProp), targetIsOptional), reportErrors); + } + } + function propertyRelatedTo(source: Type, target: Type, sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean): Ternary { const sourcePropFlags = getDeclarationModifierFlagsFromSymbol(sourceProp); const targetPropFlags = getDeclarationModifierFlagsFromSymbol(targetProp); @@ -13505,7 +13634,7 @@ namespace ts { return Ternary.False; } // If the target comes from a partial union prop, allow `undefined` in the target type - const related = isRelatedTo(getTypeOfSourceProperty(sourceProp), addOptionality(getTypeOfSymbol(targetProp), !!(getCheckFlags(targetProp) & CheckFlags.Partial)), reportErrors); + const related = isPropertySymbolTypeRelated(sourceProp, targetProp, getTypeOfSourceProperty, reportErrors); if (!related) { if (reportErrors) { reportError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(targetProp)); @@ -13617,9 +13746,6 @@ namespace ts { if (!(targetProp.flags & SymbolFlags.Prototype)) { const sourceProp = getPropertyOfType(source, targetProp.escapedName); if (sourceProp && sourceProp !== targetProp) { - if (isIgnoredJsxProperty(source, sourceProp, getTypeOfSymbol(targetProp))) { - continue; - } const related = propertyRelatedTo(source, target, sourceProp, targetProp, getTypeOfSymbol, reportErrors); if (!related) { return Ternary.False; @@ -13765,7 +13891,7 @@ namespace ts { function eachPropertyRelatedTo(source: Type, target: Type, kind: IndexKind, reportErrors: boolean): Ternary { let result = Ternary.True; for (const prop of getPropertiesOfObjectType(source)) { - if (isIgnoredJsxProperty(source, prop, /*targetMemberType*/ undefined)) { + if (isIgnoredJsxProperty(source, prop)) { continue; } // Skip over symbol-named members @@ -13977,12 +14103,6 @@ namespace ts { if (unreliable) { variance |= VarianceFlags.Unreliable; } - const covariantID = getRelationKey(typeWithSub, typeWithSuper, assignableRelation); - const contravariantID = getRelationKey(typeWithSuper, typeWithSub, assignableRelation); - // We delete the results of these checks, as we want them to actually be run, see the `Unmeasurable` variance we cache, - // And then fall back to a structural result. - assignableRelation.delete(covariantID); - assignableRelation.delete(contravariantID); } variances.push(variance); } @@ -14503,7 +14623,7 @@ namespace ts { * with no call or construct signatures. */ function isObjectTypeWithInferableIndex(type: Type) { - return type.symbol && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.ValueModule)) !== 0 && + return type.symbol && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum | SymbolFlags.ValueModule)) !== 0 && !typeHasCallOrConstructSignatures(type); } @@ -14647,26 +14767,34 @@ namespace ts { function getWidenedTypeWithContext(type: Type, context: WideningContext | undefined): Type { if (getObjectFlags(type) & ObjectFlags.RequiresWidening) { + if (context === undefined && type.widened) { + return type.widened; + } + let result: Type | undefined; if (type.flags & TypeFlags.Nullable) { - return anyType; + result = anyType; } - if (isObjectLiteralType(type)) { - return getWidenedTypeOfObjectLiteral(type, context); + else if (isObjectLiteralType(type)) { + result = getWidenedTypeOfObjectLiteral(type, context); } - if (type.flags & TypeFlags.Union) { + else if (type.flags & TypeFlags.Union) { const unionContext = context || createWideningContext(/*parent*/ undefined, /*propertyName*/ undefined, (type).types); const widenedTypes = sameMap((type).types, t => t.flags & TypeFlags.Nullable ? t : getWidenedTypeWithContext(t, unionContext)); // Widening an empty object literal transitions from a highly restrictive type to // a highly inclusive one. For that reason we perform subtype reduction here if the // union includes empty object types (e.g. reducing {} | string to just {}). - return getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType) ? UnionReduction.Subtype : UnionReduction.Literal); + result = getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType) ? UnionReduction.Subtype : UnionReduction.Literal); } - if (type.flags & TypeFlags.Intersection) { - return getIntersectionType(sameMap((type).types, getWidenedType)); + else if (type.flags & TypeFlags.Intersection) { + result = getIntersectionType(sameMap((type).types, getWidenedType)); } - if (isArrayType(type) || isTupleType(type)) { - return createTypeReference((type).target, sameMap((type).typeArguments, getWidenedType)); + else if (isArrayType(type) || isTupleType(type)) { + result = createTypeReference((type).target, sameMap((type).typeArguments, getWidenedType)); } + if (result && context === undefined) { + type.widened = result; + } + return result || type; } return type; } @@ -14832,13 +14960,6 @@ namespace ts { return context && createInferenceContextWorker(map(context.inferences, cloneInferenceInfo), context.signature, context.flags | extraFlags, context.compareTypes); } - function cloneInferredPartOfContext(context: InferenceContext): InferenceContext | undefined { - const inferences = filter(context.inferences, hasInferenceCandidates); - return inferences.length ? - createInferenceContextWorker(map(inferences, cloneInferenceInfo), context.signature, context.flags, context.compareTypes) : - undefined; - } - function createInferenceContextWorker(inferences: InferenceInfo[], signature: Signature | undefined, flags: InferenceFlags, compareTypes: TypeComparer): InferenceContext { const context: InferenceContext = { inferences, @@ -15070,11 +15191,7 @@ namespace ts { if (source.aliasSymbol && source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol) { // Source and target are types originating in the same generic type alias declaration. // Simply infer from source type arguments to target type arguments. - const sourceTypes = source.aliasTypeArguments; - const targetTypes = target.aliasTypeArguments!; - for (let i = 0; i < sourceTypes.length; i++) { - inferFromTypes(sourceTypes[i], targetTypes[i]); - } + inferFromTypeArguments(source.aliasTypeArguments, target.aliasTypeArguments!, getAliasVariances(source.aliasSymbol)); return; } if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union && !(source.flags & TypeFlags.EnumLiteral && target.flags & TypeFlags.EnumLiteral) || @@ -15180,18 +15297,7 @@ namespace ts { } if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target) { // If source and target are references to the same generic type, infer from type arguments - const sourceTypes = (source).typeArguments || emptyArray; - const targetTypes = (target).typeArguments || emptyArray; - const count = sourceTypes.length < targetTypes.length ? sourceTypes.length : targetTypes.length; - const variances = getVariances((source).target); - for (let i = 0; i < count; i++) { - if (i < variances.length && (variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Contravariant) { - inferFromContravariantTypes(sourceTypes[i], targetTypes[i]); - } - else { - inferFromTypes(sourceTypes[i], targetTypes[i]); - } - } + inferFromTypeArguments((source).typeArguments || emptyArray, (target).typeArguments || emptyArray, getVariances((source).target)); } else if (source.flags & TypeFlags.Index && target.flags & TypeFlags.Index) { contravariant = !contravariant; @@ -15311,6 +15417,18 @@ namespace ts { } } + function inferFromTypeArguments(sourceTypes: readonly Type[], targetTypes: readonly Type[], variances: readonly VarianceFlags[]) { + const count = sourceTypes.length < targetTypes.length ? sourceTypes.length : targetTypes.length; + for (let i = 0; i < count; i++) { + if (i < variances.length && (variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Contravariant) { + inferFromContravariantTypes(sourceTypes[i], targetTypes[i]); + } + else { + inferFromTypes(sourceTypes[i], targetTypes[i]); + } + } + } + function inferFromContravariantTypes(source: Type, target: Type) { if (strictFunctionTypes || priority & InferencePriority.AlwaysStrict) { contravariant = !contravariant; @@ -18150,7 +18268,7 @@ namespace ts { } // Return contextual type of parameter or undefined if no contextual type is available - function getContextuallyTypedParameterType(parameter: ParameterDeclaration): Type | undefined { + function getContextuallyTypedParameterType(parameter: ParameterDeclaration, forCache: boolean): Type | undefined { const func = parameter.parent; if (!isContextSensitiveFunctionOrObjectLiteralMethod(func)) { return undefined; @@ -18171,8 +18289,21 @@ namespace ts { links.resolvedSignature = cached; return type; } - const contextualSignature = getContextualSignature(func); + let contextualSignature = getContextualSignature(func); if (contextualSignature) { + if (forCache) { + // Calling the below guarantees the types are primed and assigned in the same way + // as when the parameter is reached via `checkFunctionExpressionOrObjectLiteralMethod`. + // This should prevent any uninstantiated inference variables in the contextual signature + // from leaking, and should lock in cached parameter types via `assignContextualParameterTypes` + // which we will then immediately use the results of below. + contextuallyCheckFunctionExpressionOrObjectLiteralMethod(func); + const type = getTypeOfSymbol(getMergedSymbol(func.symbol)); + if (isTypeAny(type)) { + return type; + } + contextualSignature = getSignaturesOfType(type, SignatureKind.Call)[0]; + } const index = func.parameters.indexOf(parameter) - (getThisParameter(func) ? 1 : 0); return parameter.dotDotDotToken && lastOrUndefined(func.parameters) === parameter ? getRestTypeAtPosition(contextualSignature, index) : @@ -18187,7 +18318,7 @@ namespace ts { } switch (declaration.kind) { case SyntaxKind.Parameter: - return getContextuallyTypedParameterType(declaration); + return getContextuallyTypedParameterType(declaration, /*forCache*/ false); case SyntaxKind.BindingElement: return getContextualTypeForBindingElement(declaration); // By default, do nothing and return undefined - only parameters and binding elements have context implied by a parent @@ -18344,11 +18475,13 @@ namespace ts { } return contextSensitive === true ? getTypeOfExpression(left) : contextSensitive; case SyntaxKind.BarBarToken: - // When an || expression has a contextual type, the operands are contextually typed by that type. When an || - // expression has no contextual type, the right operand is contextually typed by the type of the left operand, - // except for the special case of Javascript declarations of the form `namespace.prop = namespace.prop || {}` + // When an || expression has a contextual type, the operands are contextually typed by that type, except + // when that type originates in a binding pattern, the right operand is contextually typed by the type of + // the left operand. When an || expression has no contextual type, the right operand is contextually typed + // by the type of the left operand, except for the special case of Javascript declarations of the form + // `namespace.prop = namespace.prop || {}`. const type = getContextualType(binaryExpression, contextFlags); - return !type && node === right && !isDefaultedExpandoInitializer(binaryExpression) ? + return node === right && (type && type.pattern || !type && !isDefaultedExpandoInitializer(binaryExpression)) ? getTypeOfExpression(left) : type; case SyntaxKind.AmpersandAmpersandToken: case SyntaxKind.CommaToken: @@ -20088,7 +20221,8 @@ namespace ts { let propType: Type; const leftType = checkNonNullExpression(left); const parentSymbol = getNodeLinks(left).resolvedSymbol; - const apparentType = getApparentType(getWidenedType(leftType)); + // We widen array literals to get type any[] instead of undefined[] in non-strict mode + const apparentType = getApparentType(isEmptyArrayLiteralType(leftType) ? getWidenedType(leftType) : leftType); if (isTypeAny(apparentType) || apparentType === silentNeverType) { if (isIdentifier(left) && parentSymbol) { markAliasReferenced(parentSymbol, node); @@ -20101,7 +20235,7 @@ namespace ts { markAliasReferenced(parentSymbol, node); } if (!prop) { - const indexInfo = assignmentKind === AssignmentKind.None || !isGenericObjectType(leftType) ? getIndexInfoOfType(apparentType, IndexKind.String) : undefined; + const indexInfo = assignmentKind === AssignmentKind.None || !isGenericObjectType(leftType) || isThisTypeParameter(leftType) ? getIndexInfoOfType(apparentType, IndexKind.String) : undefined; if (!(indexInfo && indexInfo.type)) { if (isJSLiteralType(leftType)) { return anyType; @@ -20814,7 +20948,8 @@ namespace ts { // We clone the inference context to avoid disturbing a resolution in progress for an // outer call expression. Effectively we just want a snapshot of whatever has been // inferred for any outer call expression so far. - const outerMapper = getMapperFromContext(cloneInferenceContext(getInferenceContext(node), InferenceFlags.NoDefault)); + const outerContext = getInferenceContext(node); + const outerMapper = getMapperFromContext(cloneInferenceContext(outerContext, InferenceFlags.NoDefault)); const instantiatedType = instantiateType(contextualType, outerMapper); // If the contextual type is a generic function type with a single call signature, we // instantiate the type with its own type parameters and type arguments. This ensures that @@ -20831,8 +20966,13 @@ namespace ts { // Inferences made from return types have lower priority than all other inferences. inferTypes(context.inferences, inferenceSourceType, inferenceTargetType, InferencePriority.ReturnType); // Create a type mapper for instantiating generic contextual types using the inferences made - // from the return type. - context.returnMapper = getMapperFromContext(cloneInferredPartOfContext(context)); + // from the return type. We need a separate inference pass here because (a) instantiation of + // the source type uses the outer context's return mapper (which excludes inferences made from + // outer arguments), and (b) we don't want any further inferences going into this context. + const returnContext = createInferenceContext(signature.typeParameters!, signature, context.flags); + const returnSourceType = instantiateType(contextualType, outerContext && outerContext.returnMapper); + inferTypes(returnContext.inferences, returnSourceType, inferenceTargetType); + context.returnMapper = some(returnContext.inferences, hasInferenceCandidates) ? getMapperFromContext(returnContext) : undefined; } } @@ -22956,12 +23096,18 @@ namespace ts { checkGrammarForGenerator(node); } - const links = getNodeLinks(node); const type = getTypeOfSymbol(getMergedSymbol(node.symbol)); if (isTypeAny(type)) { return type; } + contextuallyCheckFunctionExpressionOrObjectLiteralMethod(node, checkMode); + + return type; + } + + function contextuallyCheckFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | ArrowFunction | MethodDeclaration, checkMode?: CheckMode) { + const links = getNodeLinks(node); // Check if function expression is contextually typed and assign parameter types if so. if (!(links.flags & NodeCheckFlags.ContextChecked)) { const contextualSignature = getContextualSignature(node); @@ -22971,6 +23117,10 @@ namespace ts { if (!(links.flags & NodeCheckFlags.ContextChecked)) { links.flags |= NodeCheckFlags.ContextChecked; if (contextualSignature) { + const type = getTypeOfSymbol(getMergedSymbol(node.symbol)); + if (isTypeAny(type)) { + return; + } const signature = getSignaturesOfType(type, SignatureKind.Call)[0]; if (isContextSensitive(node)) { const inferenceContext = getInferenceContext(node); @@ -22991,8 +23141,6 @@ namespace ts { checkSignatureDeclaration(node); } } - - return type; } function getReturnOrPromisedType(node: FunctionLikeDeclaration | MethodSignature, functionFlags: FunctionFlags) { @@ -29960,7 +30108,7 @@ namespace ts { // } // [ a ] from // [a] = [ some array ...] - function getTypeOfArrayLiteralOrObjectLiteralDestructuringAssignment(expr: Expression): Type { + function getTypeOfAssignmentPattern(expr: AssignmentPattern): Type | undefined { Debug.assert(expr.kind === SyntaxKind.ObjectLiteralExpression || expr.kind === SyntaxKind.ArrayLiteralExpression); // If this is from "for of" // for ( { a } of elems) { @@ -29979,17 +30127,16 @@ namespace ts { // for ({ skills: { primary, secondary } } = multiRobot, i = 0; i < 1; i++) { if (expr.parent.kind === SyntaxKind.PropertyAssignment) { const node = cast(expr.parent.parent, isObjectLiteralExpression); - const typeOfParentObjectLiteral = getTypeOfArrayLiteralOrObjectLiteralDestructuringAssignment(node); + const typeOfParentObjectLiteral = getTypeOfAssignmentPattern(node) || errorType; const propertyIndex = indexOfNode(node.properties, expr.parent); - return checkObjectLiteralDestructuringPropertyAssignment(node, typeOfParentObjectLiteral || errorType, propertyIndex)!; // TODO: GH#18217 + return checkObjectLiteralDestructuringPropertyAssignment(node, typeOfParentObjectLiteral, propertyIndex); } // Array literal assignment - array destructuring pattern - Debug.assert(expr.parent.kind === SyntaxKind.ArrayLiteralExpression); + const node = cast(expr.parent, isArrayLiteralExpression); // [{ property1: p1, property2 }] = elems; - const typeOfArrayLiteral = getTypeOfArrayLiteralOrObjectLiteralDestructuringAssignment(expr.parent); - const elementType = checkIteratedTypeOrElementType(typeOfArrayLiteral || errorType, expr.parent, /*allowStringInput*/ false, /*allowAsyncIterables*/ false) || errorType; - return checkArrayLiteralDestructuringElementAssignment(expr.parent, typeOfArrayLiteral, - (expr.parent).elements.indexOf(expr), elementType || errorType)!; // TODO: GH#18217 + const typeOfArrayLiteral = getTypeOfAssignmentPattern(node) || errorType; + const elementType = checkIteratedTypeOrElementType(typeOfArrayLiteral, expr.parent, /*allowStringInput*/ false, /*allowAsyncIterables*/ false) || errorType; + return checkArrayLiteralDestructuringElementAssignment(node, typeOfArrayLiteral, node.elements.indexOf(expr), elementType); } // Gets the property symbol corresponding to the property in destructuring assignment @@ -30000,7 +30147,7 @@ namespace ts { // [a] = [ property1, property2 ] function getPropertySymbolOfDestructuringAssignment(location: Identifier) { // Get the type of the object or array literal and then look for property of given name in the type - const typeOfObjectLiteral = getTypeOfArrayLiteralOrObjectLiteralDestructuringAssignment(location.parent.parent); + const typeOfObjectLiteral = getTypeOfAssignmentPattern(cast(location.parent.parent, isAssignmentPattern)); return typeOfObjectLiteral && getPropertyOfType(typeOfObjectLiteral, location.escapedText); } diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 3aaa217fbd0..394a94cb663 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -1022,8 +1022,7 @@ namespace ts { } } - /* @internal */ - export interface OptionsBase { + interface OptionsBase { [option: string]: CompilerOptionsValue | undefined; } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 0034c275999..f1511b79c12 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1,7 +1,7 @@ namespace ts { // WARNING: The script `configureNightly.ts` uses a regexp to parse out these values. // If changing the text in this section, be sure to test `configureNightly` too. - export const versionMajorMinor = "3.5"; + export const versionMajorMinor = "3.6"; /** The version of the TypeScript compiler release */ export const version = `${versionMajorMinor}.0-dev`; } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 101b584ca13..5d6dc7d6df4 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3927,6 +3927,10 @@ "category": "Message", "code": 6219 }, + "'package.json' had a falsy '{0}' field.": { + "category": "Message", + "code": 6220 + }, "Projects to reference": { "category": "Message", @@ -4288,6 +4292,14 @@ "category": "Error", "code": 7052 }, + "Element implicitly has an 'any' type because expression of type '{0}' can't be used to index type '{1}'.": { + "category": "Error", + "code": 7053 + }, + "No index signature with a parameter of type '{0}' was found on type '{1}'.": { + "category": "Error", + "code": 7054 + }, "You cannot rename this element.": { "category": "Error", "code": 8000 diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 07b1208688f..ddd273c3602 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -284,7 +284,6 @@ namespace ts { // Write build information if applicable if (!buildInfoPath || targetSourceFile || emitSkipped) return; const program = host.getProgramBuildInfo(); - if (!bundle && !program) return; if (host.isEmitBlocked(buildInfoPath) || compilerOptions.noEmit) { emitSkipped = true; return; @@ -638,7 +637,12 @@ namespace ts { } /*@internal*/ - export function emitUsingBuildInfo(config: ParsedCommandLine, host: EmitUsingBuildInfoHost, getCommandLine: (ref: ProjectReference) => ParsedCommandLine | undefined): EmitUsingBuildInfoResult { + export function emitUsingBuildInfo( + config: ParsedCommandLine, + host: EmitUsingBuildInfoHost, + getCommandLine: (ref: ProjectReference) => ParsedCommandLine | undefined, + customTransformers?: CustomTransformers + ): EmitUsingBuildInfoResult { const { buildInfoPath, jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath } = getOutputPathsForBundle(config.options, /*forceDtsPaths*/ false); const buildInfoText = host.readFile(Debug.assertDefined(buildInfoPath)); if (!buildInfoText) return buildInfoPath!; @@ -723,7 +727,12 @@ namespace ts { useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(), getProgramBuildInfo: returnUndefined }; - emitFiles(notImplementedResolver, emitHost, /*targetSourceFile*/ undefined, getTransformers(config.options), /*emitOnlyDtsFiles*/ false); + emitFiles( + notImplementedResolver, + emitHost, + /*targetSourceFile*/ undefined, + getTransformers(config.options, customTransformers) + ); return outputFiles; } diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index 19402b03ee9..604b82cce5e 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -141,7 +141,15 @@ namespace ts { function readPackageJsonPathField(jsonContent: PackageJson, fieldName: K, baseDirectory: string, state: ModuleResolutionState): PackageJson[K] | undefined { const fileName = readPackageJsonField(jsonContent, fieldName, "string", state); - if (fileName === undefined) return; + if (fileName === undefined) { + return; + } + if (!fileName) { + if (state.traceEnabled) { + trace(state.host, Diagnostics.package_json_had_a_falsy_0_field, fieldName); + } + return; + } const path = normalizePath(combinePaths(baseDirectory, fileName)); if (state.traceEnabled) { trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, fileName, path); diff --git a/src/compiler/moduleSpecifiers.ts b/src/compiler/moduleSpecifiers.ts index 59bb74a22c1..bc448698c69 100644 --- a/src/compiler/moduleSpecifiers.ts +++ b/src/compiler/moduleSpecifiers.ts @@ -175,9 +175,9 @@ namespace ts.moduleSpecifiers { function discoverProbableSymlinks(files: ReadonlyArray, getCanonicalFileName: GetCanonicalFileName, cwd: string): ReadonlyMap { const result = createMap(); - const symlinks = mapDefined(files, sf => - sf.resolvedModules && firstDefinedIterator(sf.resolvedModules.values(), res => - res && res.originalPath && res.resolvedFileName !== res.originalPath ? [res.resolvedFileName, res.originalPath] : undefined)); + const symlinks = flatten(mapDefined(files, sf => + sf.resolvedModules && compact(arrayFrom(mapIterator(sf.resolvedModules.values(), res => + res && res.originalPath && res.resolvedFileName !== res.originalPath ? [res.resolvedFileName, res.originalPath] as const : undefined))))); for (const [resolvedPath, originalPath] of symlinks) { const [commonResolved, commonOriginal] = guessDirectorySymlink(resolvedPath, originalPath, cwd, getCanonicalFileName); result.set(commonOriginal, commonResolved); diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index b82a5a78d71..fb04d7b7a18 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -54,6 +54,7 @@ namespace ts { writeLog(s: string): void; maxNumberOfFilesToIterateForInvalidation?: number; getCurrentProgram(): Program | undefined; + fileIsOpen(filePath: Path): boolean; } interface DirectoryWatchesOfFailedLookup { @@ -698,6 +699,11 @@ namespace ts { // If something to do with folder/file starting with "." in node_modules folder, skip it if (isPathIgnored(fileOrDirectoryPath)) return false; + // prevent saving an open file from over-eagerly triggering invalidation + if (resolutionHost.fileIsOpen(fileOrDirectoryPath)) { + return false; + } + // Some file or directory in the watching directory is created // Return early if it does not have any of the watching extension or not the custom failed lookup path const dirOfFileOrDirectory = getDirectoryPath(fileOrDirectoryPath); diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index 1c1df9bb0c2..d520571e6df 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -44,6 +44,7 @@ namespace ts { addRange(transformers, customTransformers && map(customTransformers.before, wrapScriptTransformerFactory)); transformers.push(transformTypeScript); + transformers.push(transformClassFields); if (jsx === JsxEmit.React) { transformers.push(transformJsx); diff --git a/src/compiler/transformers/classFields.ts b/src/compiler/transformers/classFields.ts new file mode 100644 index 00000000000..575e1d13346 --- /dev/null +++ b/src/compiler/transformers/classFields.ts @@ -0,0 +1,491 @@ +/*@internal*/ +namespace ts { + const enum ClassPropertySubstitutionFlags { + /** + * Enables substitutions for class expressions with static fields + * which have initializers that reference the class name. + */ + ClassAliases = 1 << 0, + } + /** + * Transforms ECMAScript Class Syntax. + * TypeScript parameter property syntax is transformed in the TypeScript transformer. + * For now, this transforms public field declarations using TypeScript class semantics + * (where the declarations get elided and initializers are transformed as assignments in the constructor). + * Eventually, this transform will change to the ECMAScript semantics (with Object.defineProperty). + */ + export function transformClassFields(context: TransformationContext) { + const { + hoistVariableDeclaration, + endLexicalEnvironment, + resumeLexicalEnvironment + } = context; + const resolver = context.getEmitResolver(); + + const previousOnSubstituteNode = context.onSubstituteNode; + context.onSubstituteNode = onSubstituteNode; + + let enabledSubstitutions: ClassPropertySubstitutionFlags; + + let classAliases: Identifier[]; + + /** + * Tracks what computed name expressions originating from elided names must be inlined + * at the next execution site, in document order + */ + let pendingExpressions: Expression[] | undefined; + + /** + * Tracks what computed name expression statements and static property initializers must be + * emitted at the next execution site, in document order (for decorated classes). + */ + let pendingStatements: Statement[] | undefined; + + return chainBundle(transformSourceFile); + + function transformSourceFile(node: SourceFile) { + if (node.isDeclarationFile) { + return node; + } + const visited = visitEachChild(node, visitor, context); + addEmitHelpers(visited, context.readEmitHelpers()); + return visited; + } + + function visitor(node: Node): VisitResult { + if (!(node.transformFlags & TransformFlags.ContainsClassFields)) return node; + + switch (node.kind) { + case SyntaxKind.ClassExpression: + return visitClassExpression(node as ClassExpression); + case SyntaxKind.ClassDeclaration: + return visitClassDeclaration(node as ClassDeclaration); + case SyntaxKind.VariableStatement: + return visitVariableStatement(node as VariableStatement); + } + return visitEachChild(node, visitor, context); + } + + /** + * Visits the members of a class that has fields. + * + * @param node The node to visit. + */ + function classElementVisitor(node: Node): VisitResult { + switch (node.kind) { + case SyntaxKind.Constructor: + // Constructors for classes using class fields are transformed in + // `visitClassDeclaration` or `visitClassExpression`. + return undefined; + + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.MethodDeclaration: + // Visit the name of the member (if it's a computed property name). + return visitEachChild(node, classElementVisitor, context); + + case SyntaxKind.PropertyDeclaration: + return visitPropertyDeclaration(node as PropertyDeclaration); + + case SyntaxKind.ComputedPropertyName: + return visitComputedPropertyName(node as ComputedPropertyName); + + default: + return node; + } + } + + function visitVariableStatement(node: VariableStatement) { + const savedPendingStatements = pendingStatements; + pendingStatements = []; + + const visitedNode = visitEachChild(node, visitor, context); + const statement = some(pendingStatements) ? + [visitedNode, ...pendingStatements] : + visitedNode; + + pendingStatements = savedPendingStatements; + return statement; + } + + function visitComputedPropertyName(name: ComputedPropertyName) { + let node = visitEachChild(name, visitor, context); + if (some(pendingExpressions)) { + const expressions = pendingExpressions; + expressions.push(name.expression); + pendingExpressions = []; + node = updateComputedPropertyName( + node, + inlineExpressions(expressions) + ); + } + return node; + } + + function visitPropertyDeclaration(node: PropertyDeclaration) { + Debug.assert(!some(node.decorators)); + // Create a temporary variable to store a computed property name (if necessary). + // If it's not inlineable, then we emit an expression after the class which assigns + // the property name to the temporary variable. + const expr = getPropertyNameExpressionIfNeeded(node.name, !!node.initializer); + if (expr && !isSimpleInlineableExpression(expr)) { + (pendingExpressions || (pendingExpressions = [])).push(expr); + } + return undefined; + } + + function visitClassDeclaration(node: ClassDeclaration) { + if (!forEach(node.members, isPropertyDeclaration)) { + return visitEachChild(node, visitor, context); + } + const savedPendingExpressions = pendingExpressions; + pendingExpressions = undefined; + + const extendsClauseElement = getEffectiveBaseTypeNode(node); + const isDerivedClass = !!(extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword); + + const statements: Statement[] = [ + updateClassDeclaration( + node, + node.decorators, + node.modifiers, + node.name, + node.typeParameters, + node.heritageClauses, + transformClassMembers(node, isDerivedClass) + ) + ]; + + // Write any pending expressions from elided or moved computed property names + if (some(pendingExpressions)) { + statements.push(createExpressionStatement(inlineExpressions(pendingExpressions!))); + } + pendingExpressions = savedPendingExpressions; + + // Emit static property assignment. Because classDeclaration is lexically evaluated, + // it is safe to emit static property assignment after classDeclaration + // From ES6 specification: + // HasLexicalDeclaration (N) : Determines if the argument identifier has a binding in this environment record that was created using + // a lexical declaration such as a LexicalDeclaration or a ClassDeclaration. + const staticProperties = getInitializedProperties(node, /*isStatic*/ true); + if (some(staticProperties)) { + addInitializedPropertyStatements(statements, staticProperties, getInternalName(node)); + } + + return statements; + } + + function visitClassExpression(node: ClassExpression): Expression { + if (!forEach(node.members, isPropertyDeclaration)) { + return visitEachChild(node, visitor, context); + } + const savedPendingExpressions = pendingExpressions; + pendingExpressions = undefined; + + // If this class expression is a transformation of a decorated class declaration, + // then we want to output the pendingExpressions as statements, not as inlined + // expressions with the class statement. + // + // In this case, we use pendingStatements to produce the same output as the + // class declaration transformation. The VariableStatement visitor will insert + // these statements after the class expression variable statement. + const isDecoratedClassDeclaration = isClassDeclaration(getOriginalNode(node)); + + const staticProperties = getInitializedProperties(node, /*isStatic*/ true); + const extendsClauseElement = getEffectiveBaseTypeNode(node); + const isDerivedClass = !!(extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword); + + const classExpression = updateClassExpression( + node, + node.modifiers, + node.name, + node.typeParameters, + visitNodes(node.heritageClauses, visitor, isHeritageClause), + transformClassMembers(node, isDerivedClass) + ); + + if (some(staticProperties) || some(pendingExpressions)) { + if (isDecoratedClassDeclaration) { + Debug.assertDefined(pendingStatements, "Decorated classes transformed by TypeScript are expected to be within a variable declaration."); + + // Write any pending expressions from elided or moved computed property names + if (pendingStatements && pendingExpressions && some(pendingExpressions)) { + pendingStatements.push(createExpressionStatement(inlineExpressions(pendingExpressions))); + } + pendingExpressions = savedPendingExpressions; + + if (pendingStatements && some(staticProperties)) { + addInitializedPropertyStatements(pendingStatements, staticProperties, getInternalName(node)); + } + return classExpression; + } + else { + const expressions: Expression[] = []; + const isClassWithConstructorReference = resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference; + const temp = createTempVariable(hoistVariableDeclaration, !!isClassWithConstructorReference); + if (isClassWithConstructorReference) { + // record an alias as the class name is not in scope for statics. + enableSubstitutionForClassAliases(); + const alias = getSynthesizedClone(temp); + alias.autoGenerateFlags &= ~GeneratedIdentifierFlags.ReservedInNestedScopes; + classAliases[getOriginalNodeId(node)] = alias; + } + + // To preserve the behavior of the old emitter, we explicitly indent + // the body of a class with static initializers. + setEmitFlags(classExpression, EmitFlags.Indented | getEmitFlags(classExpression)); + expressions.push(startOnNewLine(createAssignment(temp, classExpression))); + // Add any pending expressions leftover from elided or relocated computed property names + addRange(expressions, map(pendingExpressions, startOnNewLine)); + addRange(expressions, generateInitializedPropertyExpressions(staticProperties, temp)); + expressions.push(startOnNewLine(temp)); + + pendingExpressions = savedPendingExpressions; + return inlineExpressions(expressions); + } + } + + pendingExpressions = savedPendingExpressions; + return classExpression; + } + + function transformClassMembers(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) { + const members: ClassElement[] = []; + const constructor = transformConstructor(node, isDerivedClass); + if (constructor) { + members.push(constructor); + } + addRange(members, visitNodes(node.members, classElementVisitor, isClassElement)); + return setTextRange(createNodeArray(members), /*location*/ node.members); + } + + function transformConstructor(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) { + const constructor = visitNode(getFirstConstructorWithBody(node), visitor, isConstructorDeclaration); + const containsPropertyInitializer = forEach(node.members, isInitializedProperty); + if (!containsPropertyInitializer) { + return constructor; + } + const parameters = visitParameterList(constructor ? constructor.parameters : undefined, visitor, context); + const body = transformConstructorBody(node, constructor, isDerivedClass); + if (!body) { + return undefined; + } + return startOnNewLine( + setOriginalNode( + setTextRange( + createConstructor( + /*decorators*/ undefined, + /*modifiers*/ undefined, + parameters, + body + ), + constructor || node + ), + constructor + ) + ); + } + + function transformConstructorBody(node: ClassDeclaration | ClassExpression, constructor: ConstructorDeclaration | undefined, isDerivedClass: boolean) { + const properties = getInitializedProperties(node, /*isStatic*/ false); + + // Only generate synthetic constructor when there are property initializers to move. + if (!constructor && !some(properties)) { + return visitFunctionBody(/*node*/ undefined, visitor, context); + } + + resumeLexicalEnvironment(); + + let indexOfFirstStatement = 0; + let statements: Statement[] = []; + + if (!constructor && isDerivedClass) { + // Add a synthetic `super` call: + // + // super(...arguments); + // + statements.push( + createExpressionStatement( + createCall( + createSuper(), + /*typeArguments*/ undefined, + [createSpread(createIdentifier("arguments"))] + ) + ) + ); + } + + if (constructor) { + indexOfFirstStatement = addPrologueDirectivesAndInitialSuperCall(constructor, statements, visitor); + } + + // Add the property initializers. Transforms this: + // + // public x = 1; + // + // Into this: + // + // constructor() { + // this.x = 1; + // } + // + addInitializedPropertyStatements(statements, properties, createThis()); + + // Add existing statements, skipping the initial super call. + if (constructor) { + addRange(statements, visitNodes(constructor.body!.statements, visitor, isStatement, indexOfFirstStatement)); + } + + statements = mergeLexicalEnvironment(statements, endLexicalEnvironment()); + + return setTextRange( + createBlock( + setTextRange( + createNodeArray(statements), + /*location*/ constructor ? constructor.body!.statements : node.members + ), + /*multiLine*/ true + ), + /*location*/ constructor ? constructor.body : undefined + ); + } + + /** + * Generates assignment statements for property initializers. + * + * @param properties An array of property declarations to transform. + * @param receiver The receiver on which each property should be assigned. + */ + function addInitializedPropertyStatements(statements: Statement[], properties: ReadonlyArray, receiver: LeftHandSideExpression) { + for (const property of properties) { + const statement = createExpressionStatement(transformInitializedProperty(property, receiver)); + setSourceMapRange(statement, moveRangePastModifiers(property)); + setCommentRange(statement, property); + setOriginalNode(statement, property); + statements.push(statement); + } + } + + /** + * Generates assignment expressions for property initializers. + * + * @param properties An array of property declarations to transform. + * @param receiver The receiver on which each property should be assigned. + */ + function generateInitializedPropertyExpressions(properties: ReadonlyArray, receiver: LeftHandSideExpression) { + const expressions: Expression[] = []; + for (const property of properties) { + const expression = transformInitializedProperty(property, receiver); + startOnNewLine(expression); + setSourceMapRange(expression, moveRangePastModifiers(property)); + setCommentRange(expression, property); + setOriginalNode(expression, property); + expressions.push(expression); + } + + return expressions; + } + + /** + * Transforms a property initializer into an assignment statement. + * + * @param property The property declaration. + * @param receiver The object receiving the property assignment. + */ + function transformInitializedProperty(property: PropertyDeclaration, receiver: LeftHandSideExpression) { + // We generate a name here in order to reuse the value cached by the relocated computed name expression (which uses the same generated name) + const propertyName = isComputedPropertyName(property.name) && !isSimpleInlineableExpression(property.name.expression) + ? updateComputedPropertyName(property.name, getGeneratedNameForNode(property.name)) + : property.name; + const initializer = visitNode(property.initializer!, visitor, isExpression); + const memberAccess = createMemberAccessForPropertyName(receiver, propertyName, /*location*/ propertyName); + + return createAssignment(memberAccess, initializer); + } + + function enableSubstitutionForClassAliases() { + if ((enabledSubstitutions & ClassPropertySubstitutionFlags.ClassAliases) === 0) { + enabledSubstitutions |= ClassPropertySubstitutionFlags.ClassAliases; + + // We need to enable substitutions for identifiers. This allows us to + // substitute class names inside of a class declaration. + context.enableSubstitution(SyntaxKind.Identifier); + + // Keep track of class aliases. + classAliases = []; + } + } + + /** + * Hooks node substitutions. + * + * @param hint The context for the emitter. + * @param node The node to substitute. + */ + function onSubstituteNode(hint: EmitHint, node: Node) { + node = previousOnSubstituteNode(hint, node); + if (hint === EmitHint.Expression) { + return substituteExpression(node as Expression); + } + return node; + } + + function substituteExpression(node: Expression) { + switch (node.kind) { + case SyntaxKind.Identifier: + return substituteExpressionIdentifier(node as Identifier); + } + return node; + } + + function substituteExpressionIdentifier(node: Identifier): Expression { + return trySubstituteClassAlias(node) || node; + } + + function trySubstituteClassAlias(node: Identifier): Expression | undefined { + if (enabledSubstitutions & ClassPropertySubstitutionFlags.ClassAliases) { + if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ConstructorReferenceInClass) { + // Due to the emit for class decorators, any reference to the class from inside of the class body + // must instead be rewritten to point to a temporary variable to avoid issues with the double-bind + // behavior of class names in ES6. + // Also, when emitting statics for class expressions, we must substitute a class alias for + // constructor references in static property initializers. + const declaration = resolver.getReferencedValueDeclaration(node); + if (declaration) { + const classAlias = classAliases[declaration.id!]; // TODO: GH#18217 + if (classAlias) { + const clone = getSynthesizedClone(classAlias); + setSourceMapRange(clone, node); + setCommentRange(clone, node); + return clone; + } + } + } + } + + return undefined; + } + + + /** + * If the name is a computed property, this function transforms it, then either returns an expression which caches the + * value of the result or the expression itself if the value is either unused or safe to inline into multiple locations + * @param shouldHoist Does the expression need to be reused? (ie, for an initializer or a decorator) + */ + function getPropertyNameExpressionIfNeeded(name: PropertyName, shouldHoist: boolean): Expression | undefined { + if (isComputedPropertyName(name)) { + const expression = visitNode(name.expression, visitor, isExpression); + const innerExpression = skipPartiallyEmittedExpressions(expression); + const inlinable = isSimpleInlineableExpression(innerExpression); + const alreadyTransformed = isAssignmentExpression(innerExpression) && isGeneratedIdentifier(innerExpression.left); + if (!alreadyTransformed && !inlinable && shouldHoist) { + const generatedName = getGeneratedNameForNode(name); + hoistVariableDeclaration(generatedName); + return createAssignment(generatedName, expression); + } + return (inlinable || isIdentifier(innerExpression)) ? undefined : expression; + } + } + } + +} diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index a70fb820e79..adfe16c73f6 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -64,6 +64,7 @@ namespace ts { let currentLexicalScope: SourceFile | Block | ModuleBlock | CaseBlock; let currentNameScope: ClassDeclaration | undefined; let currentScopeFirstDeclarationsOfName: UnderscoreEscapedMap | undefined; + let currentClassHasParameterProperties: boolean | undefined; /** * Keeps track of whether expression substitution has been enabled for specific edge cases. @@ -83,12 +84,6 @@ namespace ts { */ let applicableSubstitutions: TypeScriptSubstitutionFlags; - /** - * Tracks what computed name expressions originating from elided names must be inlined - * at the next execution site, in document order - */ - let pendingExpressions: Expression[] | undefined; - return transformSourceFileOrBundle; function transformSourceFileOrBundle(node: SourceFile | Bundle) { @@ -136,6 +131,7 @@ namespace ts { const savedCurrentScope = currentLexicalScope; const savedCurrentNameScope = currentNameScope; const savedCurrentScopeFirstDeclarationsOfName = currentScopeFirstDeclarationsOfName; + const savedCurrentClassHasParameterProperties = currentClassHasParameterProperties; // Handle state changes before visiting a node. onBeforeVisitNode(node); @@ -149,6 +145,7 @@ namespace ts { currentLexicalScope = savedCurrentScope; currentNameScope = savedCurrentNameScope; + currentClassHasParameterProperties = savedCurrentClassHasParameterProperties; return visited; } @@ -321,6 +318,9 @@ namespace ts { return undefined; case SyntaxKind.PropertyDeclaration: + // Property declarations are not TypeScript syntax, but they must be visited + // for the decorator transformation. + return visitPropertyDeclaration(node as PropertyDeclaration); case SyntaxKind.IndexSignature: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: @@ -437,7 +437,6 @@ namespace ts { // - decorators // - optional `implements` heritage clause // - parameter property assignments in the constructor - // - property declarations // - index signatures // - method overload signatures return visitClassDeclaration(node); @@ -449,7 +448,6 @@ namespace ts { // - decorators // - optional `implements` heritage clause // - parameter property assignments in the constructor - // - property declarations // - index signatures // - method overload signatures return visitClassExpression(node); @@ -611,10 +609,6 @@ namespace ts { if (!isClassLikeDeclarationWithTypeScriptSyntax(node) && !(currentNamespace && hasModifier(node, ModifierFlags.Export))) { return visitEachChild(node, visitor, context); } - - const savedPendingExpressions = pendingExpressions; - pendingExpressions = undefined; - const staticProperties = getInitializedProperties(node, /*isStatic*/ true); const facts = getClassFacts(node, staticProperties); @@ -624,25 +618,11 @@ namespace ts { const name = node.name || (facts & ClassFacts.NeedsName ? getGeneratedNameForNode(node) : undefined); const classStatement = facts & ClassFacts.HasConstructorDecorators - ? createClassDeclarationHeadWithDecorators(node, name, facts) + ? createClassDeclarationHeadWithDecorators(node, name) : createClassDeclarationHeadWithoutDecorators(node, name, facts); let statements: Statement[] = [classStatement]; - // Write any pending expressions from elided or moved computed property names - if (some(pendingExpressions)) { - statements.push(createExpressionStatement(inlineExpressions(pendingExpressions!))); - } - pendingExpressions = savedPendingExpressions; - - // Emit static property assignment. Because classDeclaration is lexically evaluated, - // it is safe to emit static property assignment after classDeclaration - // From ES6 specification: - // HasLexicalDeclaration (N) : Determines if the argument identifier has a binding in this environment record that was created using - // a lexical declaration such as a LexicalDeclaration or a ClassDeclaration. - if (facts & ClassFacts.HasStaticInitializedProperties) { - addInitializedPropertyStatements(statements, staticProperties, facts & ClassFacts.UseImmediatelyInvokedFunctionExpression ? getInternalName(node) : getLocalName(node)); - } // Write any decorators of the node. addClassElementDecorationStatements(statements, node, /*isStatic*/ false); @@ -745,7 +725,7 @@ namespace ts { name, /*typeParameters*/ undefined, visitNodes(node.heritageClauses, visitor, isHeritageClause), - transformClassMembers(node, (facts & ClassFacts.IsDerivedClass) !== 0) + transformClassMembers(node) ); // To better align with the old emitter, we should not emit a trailing source map @@ -765,7 +745,7 @@ namespace ts { * Transforms a decorated class declaration and appends the resulting statements. If * the class requires an alias to avoid issues with double-binding, the alias is returned. */ - function createClassDeclarationHeadWithDecorators(node: ClassDeclaration, name: Identifier | undefined, facts: ClassFacts) { + function createClassDeclarationHeadWithDecorators(node: ClassDeclaration, name: Identifier | undefined) { // When we emit an ES6 class that has a class decorator, we must tailor the // emit to certain specific cases. // @@ -860,7 +840,7 @@ namespace ts { // ${members} // } const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause); - const members = transformClassMembers(node, (facts & ClassFacts.IsDerivedClass) !== 0); + const members = transformClassMembers(node); const classExpression = createClassExpression(/*modifiers*/ undefined, name, /*typeParameters*/ undefined, heritageClauses, members); setOriginalNode(classExpression, node); setTextRange(classExpression, location); @@ -888,49 +868,19 @@ namespace ts { return visitEachChild(node, visitor, context); } - const savedPendingExpressions = pendingExpressions; - pendingExpressions = undefined; - - const staticProperties = getInitializedProperties(node, /*isStatic*/ true); - const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause); - const members = transformClassMembers(node, some(heritageClauses, c => c.token === SyntaxKind.ExtendsKeyword)); + const members = transformClassMembers(node); const classExpression = createClassExpression( /*modifiers*/ undefined, node.name, /*typeParameters*/ undefined, - heritageClauses, + node.heritageClauses, members ); setOriginalNode(classExpression, node); setTextRange(classExpression, node); - if (some(staticProperties) || some(pendingExpressions)) { - const expressions: Expression[] = []; - const isClassWithConstructorReference = resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference; - const temp = createTempVariable(hoistVariableDeclaration, !!isClassWithConstructorReference); - if (isClassWithConstructorReference) { - // record an alias as the class name is not in scope for statics. - enableSubstitutionForClassAliases(); - const alias = getSynthesizedClone(temp); - alias.autoGenerateFlags &= ~GeneratedIdentifierFlags.ReservedInNestedScopes; - classAliases[getOriginalNodeId(node)] = alias; - } - - // To preserve the behavior of the old emitter, we explicitly indent - // the body of a class with static initializers. - setEmitFlags(classExpression, EmitFlags.Indented | getEmitFlags(classExpression)); - expressions.push(startOnNewLine(createAssignment(temp, classExpression))); - // Add any pending expressions leftover from elided or relocated computed property names - addRange(expressions, map(pendingExpressions, startOnNewLine)); - pendingExpressions = savedPendingExpressions; - addRange(expressions, generateInitializedPropertyExpressions(staticProperties, temp)); - expressions.push(startOnNewLine(temp)); - return inlineExpressions(expressions); - } - - pendingExpressions = savedPendingExpressions; return classExpression; } @@ -938,61 +888,81 @@ namespace ts { * Transforms the members of a class. * * @param node The current class. - * @param isDerivedClass A value indicating whether the class has an extends clause that does not extend 'null'. */ - function transformClassMembers(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) { + function transformClassMembers(node: ClassDeclaration | ClassExpression) { const members: ClassElement[] = []; - const constructor = transformConstructor(node, isDerivedClass); - if (constructor) { - members.push(constructor); - } - - addRange(members, visitNodes(node.members, classElementVisitor, isClassElement)); - return setTextRange(createNodeArray(members), /*location*/ node.members); - } - - /** - * Transforms (or creates) a constructor for a class. - * - * @param node The current class. - * @param isDerivedClass A value indicating whether the class has an extends clause that does not extend 'null'. - */ - function transformConstructor(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) { - // Check if we have property assignment inside class declaration. - // If there is a property assignment, we need to emit constructor whether users define it or not - // If there is no property assignment, we can omit constructor if users do not define it + const existingMembers = visitNodes(node.members, classElementVisitor, isClassElement); const constructor = getFirstConstructorWithBody(node); - const hasInstancePropertyWithInitializer = forEach(node.members, isInstanceInitializedProperty); - const hasParameterPropertyAssignments = constructor && - constructor.transformFlags & TransformFlags.ContainsTypeScriptClassSyntax && - forEach(constructor.parameters, isParameterWithPropertyAssignment); + const parametersWithPropertyAssignments = + constructor && hasTypeScriptClassSyntax(constructor) + ? filter(constructor.parameters, isParameterPropertyDeclaration) + : undefined; + if (some(parametersWithPropertyAssignments) && constructor) { + currentClassHasParameterProperties = true; - // If the class does not contain nodes that require a synthesized constructor, - // accept the current constructor if it exists. - if (!hasInstancePropertyWithInitializer && !hasParameterPropertyAssignments) { - return visitEachChild(constructor, visitor, context); - } - - const parameters = transformConstructorParameters(constructor); - const body = transformConstructorBody(node, constructor, isDerivedClass); - - // constructor(${parameters}) { - // ${body} - // } - return startOnNewLine( - setOriginalNode( - setTextRange( - createConstructor( + // Create property declarations for constructor parameter properties. + addRange( + members, + parametersWithPropertyAssignments.map(param => + createProperty( /*decorators*/ undefined, /*modifiers*/ undefined, - parameters, - body + param.name, + /*questionOrExclamationToken*/ undefined, + /*type*/ undefined, + /*initializer*/ undefined + ) + ) + ); + + const parameters = transformConstructorParameters(constructor); + const body = transformConstructorBody(node.members, constructor, parametersWithPropertyAssignments); + members.push(startOnNewLine( + setOriginalNode( + setTextRange( + createConstructor( + /*decorators*/ undefined, + /*modifiers*/ undefined, + parameters, + body + ), + constructor ), - constructor || node - ), - constructor - ) - ); + constructor + ) + )); + addRange( + members, + visitNodes( + existingMembers, + member => { + if (isPropertyDeclaration(member) && !hasStaticModifier(member) && !!member.initializer) { + const updated = updateProperty( + member, + member.decorators, + member.modifiers, + member.name, + member.questionToken, + member.type, + /*initializer*/ undefined + ); + setCommentRange(updated, node); + setSourceMapRange(updated, node); + return updated; + } + return member; + }, + isClassElement + ) + ); + } + else { + if (constructor) { + members.push(visitEachChild(constructor, visitor, context)); + } + addRange(members, existingMembers); + } + return setTextRange(createNodeArray(members), /*location*/ node.members); } /** @@ -1001,7 +971,7 @@ namespace ts { * * @param constructor The constructor declaration. */ - function transformConstructorParameters(constructor: ConstructorDeclaration | undefined) { + function transformConstructorParameters(constructor: ConstructorDeclaration) { // The ES2015 spec specifies in 14.5.14. Runtime Semantics: ClassDefinitionEvaluation: // If constructor is empty, then // If ClassHeritag_eopt is present and protoParent is not null, then @@ -1022,70 +992,54 @@ namespace ts { } /** - * Transforms (or creates) a constructor body for a class with parameter property - * assignments or instance property initializers. + * Transforms (or creates) a constructor body for a class with parameter property assignments. * * @param node The current class. * @param constructor The current class constructor. - * @param isDerivedClass A value indicating whether the class has an extends clause that does not extend 'null'. */ - function transformConstructorBody(node: ClassExpression | ClassDeclaration, constructor: ConstructorDeclaration | undefined, isDerivedClass: boolean) { + function transformConstructorBody(members: NodeArray, constructor: ConstructorDeclaration, propertyAssignments: ReadonlyArray) { let statements: Statement[] = []; let indexOfFirstStatement = 0; resumeLexicalEnvironment(); - if (constructor) { - indexOfFirstStatement = addPrologueDirectivesAndInitialSuperCall(constructor, statements); + indexOfFirstStatement = addPrologueDirectivesAndInitialSuperCall(constructor, statements, visitor); - // Add parameters with property assignments. Transforms this: - // - // constructor (public x, public y) { - // } - // - // Into this: - // - // constructor (x, y) { - // this.x = x; - // this.y = y; - // } - // - const propertyAssignments = getParametersWithPropertyAssignments(constructor); - addRange(statements, map(propertyAssignments, transformParameterWithPropertyAssignment)); - } - else if (isDerivedClass) { - // Add a synthetic `super` call: - // - // super(...arguments); - // - statements.push( - createExpressionStatement( - createCall( - createSuper(), - /*typeArguments*/ undefined, - [createSpread(createIdentifier("arguments"))] - ) - ) - ); - } - - // Add the property initializers. Transforms this: + // Add parameters with property assignments. Transforms this: // - // public x = 1; + // constructor (public x, public y) { + // } // // Into this: // - // constructor() { - // this.x = 1; + // constructor (x, y) { + // this.x = x; + // this.y = y; // } // - const properties = getInitializedProperties(node, /*isStatic*/ false); - addInitializedPropertyStatements(statements, properties, createThis()); + addRange(statements, map(propertyAssignments, transformParameterWithPropertyAssignment)); - if (constructor) { - // The class already had a constructor, so we should add the existing statements, skipping the initial super call. - addRange(statements, visitNodes(constructor.body!.statements, visitor, isStatement, indexOfFirstStatement)); - } + // Get property initializers. + const classBodyProperties = members.filter(member => isPropertyDeclaration(member) && !hasStaticModifier(member) && !!member.initializer) as PropertyDeclaration[]; + addRange(statements, classBodyProperties.map( + prop => { + const name = prop.name; + const lhs = (!isComputedPropertyName(name) || isSimpleInlineableExpression(name.expression)) ? + createMemberAccessForPropertyName(createThis(), name, prop) : + createElementAccess(createThis(), getGeneratedNameForNode(name)); + const initializerNode = createExpressionStatement( + createAssignment(lhs, prop.initializer!) + ); + setOriginalNode(initializerNode, prop); + setTextRange(initializerNode, prop); + setCommentRange(initializerNode, prop); + setSourceMapRange(initializerNode, prop); + return initializerNode; + } + )); + + // Add the existing statements, skipping the initial super call. + addRange(statements, visitNodes(constructor.body!.statements, visitor, isStatement, indexOfFirstStatement)); // End the lexical environment. statements = mergeLexicalEnvironment(statements, endLexicalEnvironment()); @@ -1093,7 +1047,7 @@ namespace ts { createBlock( setTextRange( createNodeArray(statements), - /*location*/ constructor ? constructor.body!.statements : node.members + /*location*/ constructor ? constructor.body!.statements : members ), /*multiLine*/ true ), @@ -1101,61 +1055,16 @@ namespace ts { ); } - /** - * Adds super call and preceding prologue directives into the list of statements. - * - * @param ctor The constructor node. - * @returns index of the statement that follows super call - */ - function addPrologueDirectivesAndInitialSuperCall(ctor: ConstructorDeclaration, result: Statement[]): number { - if (ctor.body) { - const statements = ctor.body.statements; - // add prologue directives to the list (if any) - const index = addPrologue(result, statements, /*ensureUseStrict*/ false, visitor); - if (index === statements.length) { - // list contains nothing but prologue directives (or empty) - exit - return index; - } - - const statement = statements[index]; - if (statement.kind === SyntaxKind.ExpressionStatement && isSuperCall((statement).expression)) { - result.push(visitNode(statement, visitor, isStatement)); - return index + 1; - } - - return index; - } - - return 0; - } - - /** - * Gets all parameters of a constructor that should be transformed into property assignments. - * - * @param node The constructor node. - */ - function getParametersWithPropertyAssignments(node: ConstructorDeclaration): ReadonlyArray { - return filter(node.parameters, isParameterWithPropertyAssignment); - } - - /** - * Determines whether a parameter should be transformed into a property assignment. - * - * @param parameter The parameter node. - */ - function isParameterWithPropertyAssignment(parameter: ParameterDeclaration) { - return hasModifier(parameter, ModifierFlags.ParameterPropertyModifier) - && isIdentifier(parameter.name); - } - /** * Transforms a parameter into a property assignment statement. * * @param node The parameter declaration. */ - function transformParameterWithPropertyAssignment(node: ParameterDeclaration) { - Debug.assert(isIdentifier(node.name)); - const name = node.name as Identifier; + function transformParameterWithPropertyAssignment(node: ParameterPropertyDeclaration) { + const name = node.name; + if (!isIdentifier(name)) { + return undefined; + } const propertyName = getMutableClone(name); setEmitFlags(propertyName, EmitFlags.NoComments | EmitFlags.NoSourceMap); @@ -1184,99 +1093,6 @@ namespace ts { ); } - /** - * Gets all property declarations with initializers on either the static or instance side of a class. - * - * @param node The class node. - * @param isStatic A value indicating whether to get properties from the static or instance side of the class. - */ - function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): ReadonlyArray { - return filter(node.members, isStatic ? isStaticInitializedProperty : isInstanceInitializedProperty); - } - - /** - * Gets a value indicating whether a class element is a static property declaration with an initializer. - * - * @param member The class element node. - */ - function isStaticInitializedProperty(member: ClassElement): member is PropertyDeclaration { - return isInitializedProperty(member, /*isStatic*/ true); - } - - /** - * Gets a value indicating whether a class element is an instance property declaration with an initializer. - * - * @param member The class element node. - */ - function isInstanceInitializedProperty(member: ClassElement): member is PropertyDeclaration { - return isInitializedProperty(member, /*isStatic*/ false); - } - - /** - * Gets a value indicating whether a class element is either a static or an instance property declaration with an initializer. - * - * @param member The class element node. - * @param isStatic A value indicating whether the member should be a static or instance member. - */ - function isInitializedProperty(member: ClassElement, isStatic: boolean) { - return member.kind === SyntaxKind.PropertyDeclaration - && isStatic === hasModifier(member, ModifierFlags.Static) - && (member).initializer !== undefined; - } - - /** - * Generates assignment statements for property initializers. - * - * @param properties An array of property declarations to transform. - * @param receiver The receiver on which each property should be assigned. - */ - function addInitializedPropertyStatements(statements: Statement[], properties: ReadonlyArray, receiver: LeftHandSideExpression) { - for (const property of properties) { - const statement = createExpressionStatement(transformInitializedProperty(property, receiver)); - setSourceMapRange(statement, moveRangePastModifiers(property)); - setCommentRange(statement, property); - setOriginalNode(statement, property); - statements.push(statement); - } - } - - /** - * Generates assignment expressions for property initializers. - * - * @param properties An array of property declarations to transform. - * @param receiver The receiver on which each property should be assigned. - */ - function generateInitializedPropertyExpressions(properties: ReadonlyArray, receiver: LeftHandSideExpression) { - const expressions: Expression[] = []; - for (const property of properties) { - const expression = transformInitializedProperty(property, receiver); - startOnNewLine(expression); - setSourceMapRange(expression, moveRangePastModifiers(property)); - setCommentRange(expression, property); - setOriginalNode(expression, property); - expressions.push(expression); - } - - return expressions; - } - - /** - * Transforms a property initializer into an assignment statement. - * - * @param property The property declaration. - * @param receiver The object receiving the property assignment. - */ - function transformInitializedProperty(property: PropertyDeclaration, receiver: LeftHandSideExpression) { - // We generate a name here in order to reuse the value cached by the relocated computed name expression (which uses the same generated name) - const propertyName = isComputedPropertyName(property.name) && !isSimpleInlineableExpression(property.name.expression) - ? updateComputedPropertyName(property.name, getGeneratedNameForNode(property.name)) - : property.name; - const initializer = visitNode(property.initializer!, visitor, isExpression); - const memberAccess = createMemberAccessForPropertyName(receiver, propertyName, /*location*/ propertyName); - - return createAssignment(memberAccess, initializer); - } - /** * Gets either the static or instance members of a class that are decorated, or have * parameters that are decorated. @@ -2144,16 +1960,6 @@ namespace ts { : createIdentifier("BigInt"); } - /** - * A simple inlinable expression is an expression which can be copied into multiple locations - * without risk of repeating any sideeffects and whose value could not possibly change between - * any such locations - */ - function isSimpleInlineableExpression(expression: Expression) { - return !isIdentifier(expression) && isSimpleCopiableExpression(expression) || - isWellKnownSymbolSyntactically(expression); - } - /** * Gets an expression that represents a property name. For a computed property, a * name is generated for the node. @@ -2175,26 +1981,6 @@ namespace ts { } } - /** - * If the name is a computed property, this function transforms it, then either returns an expression which caches the - * value of the result or the expression itself if the value is either unused or safe to inline into multiple locations - * @param shouldHoist Does the expression need to be reused? (ie, for an initializer or a decorator) - * @param omitSimple Should expressions with no observable side-effects be elided? (ie, the expression is not hoisted for a decorator or initializer and is a literal) - */ - function getPropertyNameExpressionIfNeeded(name: PropertyName, shouldHoist: boolean, omitSimple: boolean): Expression | undefined { - if (isComputedPropertyName(name)) { - const expression = visitNode(name.expression, visitor, isExpression); - const innerExpression = skipPartiallyEmittedExpressions(expression); - const inlinable = isSimpleInlineableExpression(innerExpression); - if (!inlinable && shouldHoist) { - const generatedName = getGeneratedNameForNode(name); - hoistVariableDeclaration(generatedName); - return createAssignment(generatedName, expression); - } - return (omitSimple && (inlinable || isIdentifier(innerExpression))) ? undefined : expression; - } - } - /** * Visits the property name of a class element, for use when emitting property * initializers. For a computed property on a node with decorators, a temporary @@ -2204,18 +1990,20 @@ namespace ts { */ function visitPropertyNameOfClassElement(member: ClassElement): PropertyName { const name = member.name!; - let expr = getPropertyNameExpressionIfNeeded(name, some(member.decorators), /*omitSimple*/ false); - if (expr) { // expr only exists if `name` is a computed property name - // Inline any pending expressions from previous elided or relocated computed property name expressions in order to preserve execution order - if (some(pendingExpressions)) { - expr = inlineExpressions([...pendingExpressions, expr]); - pendingExpressions.length = 0; + // Computed property names need to be transformed into a hoisted variable when they are used more than once. + // The names are used more than once when: + // - the property is non-static and its initializer is moved to the constructor (when there are parameter property assignments). + // - the property has a decorator. + if (isComputedPropertyName(name) && ((!hasStaticModifier(member) && currentClassHasParameterProperties) || some(member.decorators))) { + const expression = visitNode(name.expression, visitor, isExpression); + const innerExpression = skipPartiallyEmittedExpressions(expression); + if (!isSimpleInlineableExpression(innerExpression)) { + const generatedName = getGeneratedNameForNode(name); + hoistVariableDeclaration(generatedName); + return updateComputedPropertyName(name, createAssignment(generatedName, expression)); } - return updateComputedPropertyName(name as ComputedPropertyName, expr); - } - else { - return name; } + return visitNode(name, visitor, isPropertyName); } /** @@ -2261,12 +2049,23 @@ namespace ts { return !nodeIsMissing(node.body); } - function visitPropertyDeclaration(node: PropertyDeclaration): undefined { - const expr = getPropertyNameExpressionIfNeeded(node.name, some(node.decorators) || !!node.initializer, /*omitSimple*/ true); - if (expr && !isSimpleInlineableExpression(expr)) { - (pendingExpressions || (pendingExpressions = [])).push(expr); + function visitPropertyDeclaration(node: PropertyDeclaration) { + const updated = updateProperty( + node, + /*decorators*/ undefined, + visitNodes(node.modifiers, visitor, isModifier), + visitPropertyNameOfClassElement(node), + /*questionOrExclamationToken*/ undefined, + /*type*/ undefined, + visitNode(node.initializer, visitor) + ); + if (updated !== node) { + // While we emit the source map for the node after skipping decorators and modifiers, + // we need to emit the comments for the original range. + setCommentRange(updated, node); + setSourceMapRange(updated, moveRangePastDecorators(node)); } - return undefined; + return updated; } function visitConstructor(node: ConstructorDeclaration) { diff --git a/src/compiler/transformers/utilities.ts b/src/compiler/transformers/utilities.ts index 09239d7765f..f5f8a298a49 100644 --- a/src/compiler/transformers/utilities.ts +++ b/src/compiler/transformers/utilities.ts @@ -240,6 +240,47 @@ namespace ts { isIdentifier(expression); } + /** + * A simple inlinable expression is an expression which can be copied into multiple locations + * without risk of repeating any sideeffects and whose value could not possibly change between + * any such locations + */ + export function isSimpleInlineableExpression(expression: Expression) { + return !isIdentifier(expression) && isSimpleCopiableExpression(expression) || + isWellKnownSymbolSyntactically(expression); + } + + /** + * Adds super call and preceding prologue directives into the list of statements. + * + * @param ctor The constructor node. + * @param result The list of statements. + * @param visitor The visitor to apply to each node added to the result array. + * @returns index of the statement that follows super call + */ + export function addPrologueDirectivesAndInitialSuperCall(ctor: ConstructorDeclaration, result: Statement[], visitor: Visitor): number { + if (ctor.body) { + const statements = ctor.body.statements; + // add prologue directives to the list (if any) + const index = addPrologue(result, statements, /*ensureUseStrict*/ false, visitor); + if (index === statements.length) { + // list contains nothing but prologue directives (or empty) - exit + return index; + } + + const statement = statements[index]; + if (statement.kind === SyntaxKind.ExpressionStatement && isSuperCall((statement).expression)) { + result.push(visitNode(statement, visitor, isStatement)); + return index + 1; + } + + return index; + } + + return 0; + } + + /** * @param input Template string input strings * @param args Names which need to be made file-level unique @@ -255,4 +296,43 @@ namespace ts { return result; }; } + + /** + * Gets all property declarations with initializers on either the static or instance side of a class. + * + * @param node The class node. + * @param isStatic A value indicating whether to get properties from the static or instance side of the class. + */ + export function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): ReadonlyArray { + return filter(node.members, isStatic ? isStaticInitializedProperty : isInstanceInitializedProperty); + } + + /** + * Gets a value indicating whether a class element is a static property declaration with an initializer. + * + * @param member The class element node. + */ + export function isStaticInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } { + return isInitializedProperty(member) && hasStaticModifier(member); + } + + /** + * Gets a value indicating whether a class element is an instance property declaration with an initializer. + * + * @param member The class element node. + */ + export function isInstanceInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } { + return isInitializedProperty(member) && !hasStaticModifier(member); + } + + /** + * Gets a value indicating whether a class element is either a static or an instance property declaration with an initializer. + * + * @param member The class element node. + * @param isStatic A value indicating whether the member should be a static or instance member. + */ + export function isInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } { + return member.kind === SyntaxKind.PropertyDeclaration + && (member).initializer !== undefined; + } } \ No newline at end of file diff --git a/src/compiler/tsbuild.ts b/src/compiler/tsbuild.ts index a5eae8922da..94718a1b368 100644 --- a/src/compiler/tsbuild.ts +++ b/src/compiler/tsbuild.ts @@ -1,64 +1,5 @@ -// Currently we do not want to expose API for build, we should work out the API, and then expose it just like we did for builder/watch /*@internal*/ namespace ts { - const minimumDate = new Date(-8640000000000000); - const maximumDate = new Date(8640000000000000); - - export interface BuildHost { - verbose(diag: DiagnosticMessage, ...args: string[]): void; - error(diag: DiagnosticMessage, ...args: string[]): void; - errorDiagnostic(diag: Diagnostic): void; - message(diag: DiagnosticMessage, ...args: string[]): void; - } - - interface DependencyGraph { - buildQueue: ResolvedConfigFileName[]; - /** value in config File map is true if project is referenced using prepend */ - referencingProjectsMap: ConfigFileMap>; - } - - export interface BuildOptions extends OptionsBase { - dry?: boolean; - force?: boolean; - verbose?: boolean; - - /*@internal*/ clean?: boolean; - /*@internal*/ watch?: boolean; - /*@internal*/ help?: boolean; - - preserveWatchOutput?: boolean; - listEmittedFiles?: boolean; - listFiles?: boolean; - pretty?: boolean; - incremental?: boolean; - - traceResolution?: boolean; - /* @internal */ diagnostics?: boolean; - /* @internal */ extendedDiagnostics?: boolean; - } - - enum BuildResultFlags { - None = 0, - - /** - * No errors of any kind occurred during build - */ - Success = 1 << 0, - /** - * None of the .d.ts files emitted by this build were - * different from the existing files on disk - */ - DeclarationOutputUnchanged = 1 << 1, - - ConfigFileErrors = 1 << 2, - SyntaxErrors = 1 << 3, - TypeErrors = 1 << 4, - DeclarationEmitErrors = 1 << 5, - EmitErrors = 1 << 6, - - AnyErrors = ConfigFileErrors | SyntaxErrors | TypeErrors | DeclarationEmitErrors | EmitErrors - } - export enum UpToDateStatusType { Unbuildable, UpToDate, @@ -200,80 +141,93 @@ namespace ts { } } - interface FileMap { - setValue(fileName: U, value: T): void; - getValue(fileName: U): T | undefined; - hasKey(fileName: U): boolean; - removeKey(fileName: U): void; - forEach(action: (value: T, key: V) => void): void; - getSize(): number; + export function resolveConfigFileProjectName(project: string): ResolvedConfigFileName { + if (fileExtensionIs(project, Extension.Json)) { + return project as ResolvedConfigFileName; + } + + return combinePaths(project, "tsconfig.json") as ResolvedConfigFileName; + } +} + +namespace ts { + const minimumDate = new Date(-8640000000000000); + const maximumDate = new Date(8640000000000000); + + export interface BuildOptions { + dry?: boolean; + force?: boolean; + verbose?: boolean; + + /*@internal*/ clean?: boolean; + /*@internal*/ watch?: boolean; + /*@internal*/ help?: boolean; + + /*@internal*/ preserveWatchOutput?: boolean; + /*@internal*/ listEmittedFiles?: boolean; + /*@internal*/ listFiles?: boolean; + /*@internal*/ pretty?: boolean; + incremental?: boolean; + + traceResolution?: boolean; + /* @internal */ diagnostics?: boolean; + /* @internal */ extendedDiagnostics?: boolean; + + [option: string]: CompilerOptionsValue | undefined; + } + + enum BuildResultFlags { + None = 0, + + /** + * No errors of any kind occurred during build + */ + Success = 1 << 0, + /** + * None of the .d.ts files emitted by this build were + * different from the existing files on disk + */ + DeclarationOutputUnchanged = 1 << 1, + + ConfigFileErrors = 1 << 2, + SyntaxErrors = 1 << 3, + TypeErrors = 1 << 4, + DeclarationEmitErrors = 1 << 5, + EmitErrors = 1 << 6, + + AnyErrors = ConfigFileErrors | SyntaxErrors | TypeErrors | DeclarationEmitErrors | EmitErrors + } + + /*@internal*/ + export type ResolvedConfigFilePath = ResolvedConfigFileName & Path; + interface FileMap extends Map { + get(key: U): T | undefined; + has(key: U): boolean; + forEach(action: (value: T, key: U) => void): void; + readonly size: number; + keys(): Iterator; + values(): Iterator; + entries(): Iterator<[U, T]>; + set(key: U, value: T): this; + delete(key: U): boolean; clear(): void; } - - type ResolvedConfigFilePath = ResolvedConfigFileName & Path; - type ConfigFileMap = FileMap; - type ToResolvedConfigFilePath = (fileName: ResolvedConfigFileName) => ResolvedConfigFilePath; - type ToPath = (fileName: string) => Path; - - /** - * A FileMap maintains a normalized-key to value relationship - */ - function createFileMap(toPath: ToResolvedConfigFilePath): ConfigFileMap; - function createFileMap(toPath: ToPath): FileMap; - function createFileMap(toPath: (fileName: U) => V): FileMap { - // tslint:disable-next-line:no-null-keyword - const lookup = createMap(); - - return { - setValue, - getValue, - removeKey, - forEach, - hasKey, - getSize, - clear - }; - - function forEach(action: (value: T, key: V) => void) { - lookup.forEach(action); - } - - function hasKey(fileName: U) { - return lookup.has(toPath(fileName)); - } - - function removeKey(fileName: U) { - lookup.delete(toPath(fileName)); - } - - function setValue(fileName: U, value: T) { - lookup.set(toPath(fileName), value); - } - - function getValue(fileName: U): T | undefined { - return lookup.get(toPath(fileName)); - } - - function getSize() { - return lookup.size; - } - - function clear() { - lookup.clear(); - } + type ConfigFileMap = FileMap; + function createConfigFileMap(): ConfigFileMap { + return createMap() as ConfigFileMap; } - function getOrCreateValueFromConfigFileMap(configFileMap: ConfigFileMap, resolved: ResolvedConfigFileName, createT: () => T): T { - const existingValue = configFileMap.getValue(resolved); + function getOrCreateValueFromConfigFileMap(configFileMap: ConfigFileMap, resolved: ResolvedConfigFilePath, createT: () => T): T { + const existingValue = configFileMap.get(resolved); let newValue: T | undefined; if (!existingValue) { newValue = createT(); - configFileMap.setValue(resolved, newValue); + configFileMap.set(resolved, newValue); } return existingValue || newValue!; } - function getOrCreateValueMapFromConfigFileMap(configFileMap: ConfigFileMap>, resolved: ResolvedConfigFileName): Map { + function getOrCreateValueMapFromConfigFileMap(configFileMap: ConfigFileMap>, resolved: ResolvedConfigFilePath): Map { return getOrCreateValueFromConfigFileMap>(configFileMap, resolved, createMap); } @@ -285,10 +239,20 @@ namespace ts { return fileExtensionIs(fileName, Extension.Dts); } + export type ReportEmitErrorSummary = (errorCount: number) => void; + export interface SolutionBuilderHostBase extends ProgramHost { + createDirectory?(path: string): void; + /** + * Should provide create directory and writeFile if done of invalidatedProjects is not invoked with + * writeFileCallback + */ + writeFile?(path: string, data: string, writeByteOrderMark?: boolean): void; + getModifiedTime(fileName: string): Date | undefined; setModifiedTime(fileName: string, date: Date): void; deleteFile(fileName: string): void; + getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined; reportDiagnostic: DiagnosticReporter; // Technically we want to move it out and allow steps of actions on Solution, but for now just merge stuff in build host here reportSolutionBuilderStatus: DiagnosticReporter; @@ -298,7 +262,7 @@ namespace ts { afterProgramEmitAndDiagnostics?(program: T): void; // For testing - now?(): Date; + /*@internal*/ now?(): Date; } export interface SolutionBuilderHost extends SolutionBuilderHostBase { @@ -308,23 +272,20 @@ namespace ts { export interface SolutionBuilderWithWatchHost extends SolutionBuilderHostBase, WatchHost { } - export interface SolutionBuilder { - buildAllProjects(): ExitStatus; - cleanAllProjects(): ExitStatus; + export interface SolutionBuilder { + build(project?: string, cancellationToken?: CancellationToken): ExitStatus; + clean(project?: string): ExitStatus; + buildReferences(project: string, cancellationToken?: CancellationToken): ExitStatus; + cleanReferences(project?: string): ExitStatus; + getNextInvalidatedProject(cancellationToken?: CancellationToken): InvalidatedProject | undefined; - // TODO:: All the below ones should technically only be in watch mode. but thats for later time - /*@internal*/ resolveProjectName(name: string): ResolvedConfigFileName; - /*@internal*/ getUpToDateStatusOfFile(configFileName: ResolvedConfigFileName): UpToDateStatus; - /*@internal*/ getBuildGraph(configFileNames: ReadonlyArray): DependencyGraph; + // Currently used for testing but can be made public if needed: + /*@internal*/ getBuildOrder(): ReadonlyArray; - /*@internal*/ invalidateProject(configFileName: string, reloadLevel?: ConfigFileProgramReloadLevel): void; - /*@internal*/ buildInvalidatedProject(): void; - - /*@internal*/ resetBuildContext(opts?: BuildOptions): void; - } - - export interface SolutionBuilderWithWatch extends SolutionBuilder { - /*@internal*/ startWatching(): void; + // Testing only + /*@internal*/ getUpToDateStatusOfProject(project: string): UpToDateStatus; + /*@internal*/ invalidateProject(configFilePath: ResolvedConfigFilePath, reloadLevel?: ConfigFileProgramReloadLevel): void; + /*@internal*/ buildNextInvalidatedProject(): void; } /** @@ -369,823 +330,687 @@ namespace ts { return result; } - /** - * A SolutionBuilder has an immutable set of rootNames that are the "entry point" projects, but - * can dynamically add/remove other projects based on changes on the rootNames' references - * TODO: use SolutionBuilderWithWatchHost => watchedSolution - * use SolutionBuilderHost => Solution - */ - export function createSolutionBuilder(host: SolutionBuilderHost, rootNames: ReadonlyArray, defaultOptions: BuildOptions): SolutionBuilder; - export function createSolutionBuilder(host: SolutionBuilderWithWatchHost, rootNames: ReadonlyArray, defaultOptions: BuildOptions): SolutionBuilderWithWatch; - export function createSolutionBuilder(host: SolutionBuilderHost | SolutionBuilderWithWatchHost, rootNames: ReadonlyArray, defaultOptions: BuildOptions): SolutionBuilderWithWatch { - const hostWithWatch = host as SolutionBuilderWithWatchHost; + export function createSolutionBuilder(host: SolutionBuilderHost, rootNames: ReadonlyArray, defaultOptions: BuildOptions): SolutionBuilder { + return createSolutionBuilderWorker(/*watch*/ false, host, rootNames, defaultOptions); + } + + export function createSolutionBuilderWithWatch(host: SolutionBuilderWithWatchHost, rootNames: ReadonlyArray, defaultOptions: BuildOptions): SolutionBuilder { + return createSolutionBuilderWorker(/*watch*/ true, host, rootNames, defaultOptions); + } + + type ConfigFileCacheEntry = ParsedCommandLine | Diagnostic; + interface SolutionBuilderStateCache { + originalReadFile: CompilerHost["readFile"]; + originalFileExists: CompilerHost["fileExists"]; + originalDirectoryExists: CompilerHost["directoryExists"]; + originalCreateDirectory: CompilerHost["createDirectory"]; + originalWriteFile: CompilerHost["writeFile"] | undefined; + originalReadFileWithCache: CompilerHost["readFile"]; + originalGetSourceFile: CompilerHost["getSourceFile"]; + } + + interface SolutionBuilderState { + readonly host: SolutionBuilderHost; + readonly hostWithWatch: SolutionBuilderWithWatchHost; + readonly currentDirectory: string; + readonly getCanonicalFileName: GetCanonicalFileName; + readonly parseConfigFileHost: ParseConfigFileHost; + readonly writeFileName: ((s: string) => void) | undefined; + + // State of solution + readonly options: BuildOptions; + readonly baseCompilerOptions: CompilerOptions; + readonly rootNames: ReadonlyArray; + + readonly resolvedConfigFilePaths: Map; + readonly configFileCache: ConfigFileMap; + /** Map from config file name to up-to-date status */ + readonly projectStatus: ConfigFileMap; + readonly buildInfoChecked: ConfigFileMap; + readonly extendedConfigCache: Map; + + readonly builderPrograms: ConfigFileMap; + readonly diagnostics: ConfigFileMap; + readonly projectPendingBuild: ConfigFileMap; + readonly projectErrorsReported: ConfigFileMap; + + readonly compilerHost: CompilerHost; + readonly moduleResolutionCache: ModuleResolutionCache | undefined; + + // Mutable state + buildOrder: readonly ResolvedConfigFileName[] | undefined; + readFileWithCache: (f: string) => string | undefined; + projectCompilerOptions: CompilerOptions; + cache: SolutionBuilderStateCache | undefined; + allProjectBuildPending: boolean; + needsSummary: boolean; + watchAllProjectsPending: boolean; + currentInvalidatedProject: InvalidatedProject | undefined; + + // Watch state + readonly watch: boolean; + readonly allWatchedWildcardDirectories: ConfigFileMap>; + readonly allWatchedInputFiles: ConfigFileMap>; + readonly allWatchedConfigFiles: ConfigFileMap; + + timerToBuildInvalidatedProject: any; + reportFileChangeDetected: boolean; + watchFile: WatchFile; + watchFilePath: WatchFilePath; + watchDirectory: WatchDirectory; + writeLog: (s: string) => void; + } + + function createSolutionBuilderState(watch: boolean, hostOrHostWithWatch: SolutionBuilderHost | SolutionBuilderWithWatchHost, rootNames: ReadonlyArray, options: BuildOptions): SolutionBuilderState { + const host = hostOrHostWithWatch as SolutionBuilderHost; + const hostWithWatch = hostOrHostWithWatch as SolutionBuilderWithWatchHost; const currentDirectory = host.getCurrentDirectory(); const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames()); - const parseConfigFileHost = parseConfigHostFromCompilerHostLike(host); // State of the solution - let options = defaultOptions; - let baseCompilerOptions = getCompilerOptionsOfBuildOptions(options); - type ConfigFileCacheEntry = ParsedCommandLine | Diagnostic; - const configFileCache = createFileMap(toPath); - /** Map from output file name to its pre-build timestamp */ - const unchangedOutputs = createFileMap(toPath as ToPath); - /** Map from config file name to up-to-date status */ - const projectStatus = createFileMap(toPath); - const missingRoots = createMap(); - let globalDependencyGraph: DependencyGraph | undefined; - const writeFileName = host.trace ? (s: string) => host.trace!(s) : undefined; - let readFileWithCache = (f: string) => host.readFile(f); - let projectCompilerOptions = baseCompilerOptions; - const compilerHost = createCompilerHostFromProgramHost(host, () => projectCompilerOptions); + const baseCompilerOptions = getCompilerOptionsOfBuildOptions(options); + const compilerHost = createCompilerHostFromProgramHost(host, () => state.projectCompilerOptions); setGetSourceFileAsHashVersioned(compilerHost, host); - compilerHost.getParsedCommandLine = parseConfigFile; - + compilerHost.getParsedCommandLine = fileName => parseConfigFile(state, fileName as ResolvedConfigFileName, toResolvedConfigFilePath(state, fileName as ResolvedConfigFileName)); compilerHost.resolveModuleNames = maybeBind(host, host.resolveModuleNames); compilerHost.resolveTypeReferenceDirectives = maybeBind(host, host.resolveTypeReferenceDirectives); const moduleResolutionCache = !compilerHost.resolveModuleNames ? createModuleResolutionCache(currentDirectory, getCanonicalFileName) : undefined; - let cacheState: { - originalReadFile: CompilerHost["readFile"]; - originalFileExists: CompilerHost["fileExists"]; - originalDirectoryExists: CompilerHost["directoryExists"]; - originalCreateDirectory: CompilerHost["createDirectory"]; - originalWriteFile: CompilerHost["writeFile"] | undefined; - originalReadFileWithCache: CompilerHost["readFile"]; - originalGetSourceFile: CompilerHost["getSourceFile"]; - originalResolveModuleNames: CompilerHost["resolveModuleNames"]; - } | undefined; + if (!compilerHost.resolveModuleNames) { + const loader = (moduleName: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined) => resolveModuleName(moduleName, containingFile, state.projectCompilerOptions, compilerHost, moduleResolutionCache, redirectedReference).resolvedModule!; + compilerHost.resolveModuleNames = (moduleNames, containingFile, _reusedNames, redirectedReference) => + loadWithLocalCache(Debug.assertEachDefined(moduleNames), containingFile, redirectedReference, loader); + } - const buildInfoChecked = createFileMap(toPath); - const extendedConfigCache = createMap(); + const { watchFile, watchFilePath, watchDirectory, writeLog } = createWatchFactory(hostWithWatch, options); - // Watch state - const builderPrograms = createFileMap(toPath); - const diagnostics = createFileMap>(toPath); - const projectPendingBuild = createFileMap(toPath); - const projectErrorsReported = createFileMap(toPath); - const invalidatedProjectQueue = [] as ResolvedConfigFileName[]; - let nextProjectToBuild = 0; - let timerToBuildInvalidatedProject: any; - let reportFileChangeDetected = false; - const { watchFile, watchFilePath, watchDirectory, writeLog } = createWatchFactory(host, options); + const state: SolutionBuilderState = { + host, + hostWithWatch, + currentDirectory, + getCanonicalFileName, + parseConfigFileHost: parseConfigHostFromCompilerHostLike(host), + writeFileName: host.trace ? (s: string) => host.trace!(s) : undefined, - // Watches for the solution - const allWatchedWildcardDirectories = createFileMap>(toPath); - const allWatchedInputFiles = createFileMap>(toPath); - const allWatchedConfigFiles = createFileMap(toPath); + // State of solution + options, + baseCompilerOptions, + rootNames, - return { - buildAllProjects, - getUpToDateStatusOfFile, - cleanAllProjects, - resetBuildContext, - getBuildGraph, + resolvedConfigFilePaths: createMap(), + configFileCache: createConfigFileMap(), + projectStatus: createConfigFileMap(), + buildInfoChecked: createConfigFileMap(), + extendedConfigCache: createMap(), - invalidateProject, - buildInvalidatedProject, + builderPrograms: createConfigFileMap(), + diagnostics: createConfigFileMap(), + projectPendingBuild: createConfigFileMap(), + projectErrorsReported: createConfigFileMap(), - resolveProjectName, + compilerHost, + moduleResolutionCache, - startWatching + // Mutable state + buildOrder: undefined, + readFileWithCache: f => host.readFile(f), + projectCompilerOptions: baseCompilerOptions, + cache: undefined, + allProjectBuildPending: true, + needsSummary: true, + watchAllProjectsPending: watch, + currentInvalidatedProject: undefined, + + // Watch state + watch, + allWatchedWildcardDirectories: createConfigFileMap(), + allWatchedInputFiles: createConfigFileMap(), + allWatchedConfigFiles: createConfigFileMap(), + + timerToBuildInvalidatedProject: undefined, + reportFileChangeDetected: false, + watchFile, + watchFilePath, + watchDirectory, + writeLog, }; - function toPath(fileName: ResolvedConfigFileName): ResolvedConfigFilePath; - function toPath(fileName: string): Path; - function toPath(fileName: string) { - return ts.toPath(fileName, currentDirectory, getCanonicalFileName); + return state; + } + + function toPath(state: SolutionBuilderState, fileName: string) { + return ts.toPath(fileName, state.currentDirectory, state.getCanonicalFileName); + } + + function toResolvedConfigFilePath(state: SolutionBuilderState, fileName: ResolvedConfigFileName): ResolvedConfigFilePath { + const { resolvedConfigFilePaths } = state; + const path = resolvedConfigFilePaths.get(fileName); + if (path !== undefined) return path; + + const resolvedPath = toPath(state, fileName) as ResolvedConfigFilePath; + resolvedConfigFilePaths.set(fileName, resolvedPath); + return resolvedPath; + } + + function isParsedCommandLine(entry: ConfigFileCacheEntry): entry is ParsedCommandLine { + return !!(entry as ParsedCommandLine).options; + } + + function parseConfigFile(state: SolutionBuilderState, configFileName: ResolvedConfigFileName, configFilePath: ResolvedConfigFilePath): ParsedCommandLine | undefined { + const { configFileCache } = state; + const value = configFileCache.get(configFilePath); + if (value) { + return isParsedCommandLine(value) ? value : undefined; } - function resetBuildContext(opts = defaultOptions) { - options = opts; - baseCompilerOptions = getCompilerOptionsOfBuildOptions(options); - configFileCache.clear(); - unchangedOutputs.clear(); - projectStatus.clear(); - missingRoots.clear(); - globalDependencyGraph = undefined; - buildInfoChecked.clear(); - - diagnostics.clear(); - projectPendingBuild.clear(); - projectErrorsReported.clear(); - invalidatedProjectQueue.length = 0; - nextProjectToBuild = 0; - if (timerToBuildInvalidatedProject) { - clearTimeout(timerToBuildInvalidatedProject); - timerToBuildInvalidatedProject = undefined; - } - reportFileChangeDetected = false; - clearMap(allWatchedWildcardDirectories, wildCardWatches => clearMap(wildCardWatches, closeFileWatcherOf)); - clearMap(allWatchedInputFiles, inputFileWatches => clearMap(inputFileWatches, closeFileWatcher)); - clearMap(allWatchedConfigFiles, closeFileWatcher); - builderPrograms.clear(); + let diagnostic: Diagnostic | undefined; + const { parseConfigFileHost, baseCompilerOptions, extendedConfigCache, host } = state; + let parsed: ParsedCommandLine | undefined; + if (host.getParsedCommandLine) { + parsed = host.getParsedCommandLine(configFileName); + if (!parsed) diagnostic = createCompilerDiagnostic(Diagnostics.File_0_not_found, configFileName); } - - function isParsedCommandLine(entry: ConfigFileCacheEntry): entry is ParsedCommandLine { - return !!(entry as ParsedCommandLine).options; - } - - function parseConfigFile(configFilePath: ResolvedConfigFileName): ParsedCommandLine | undefined { - const value = configFileCache.getValue(configFilePath); - if (value) { - return isParsedCommandLine(value) ? value : undefined; - } - - let diagnostic: Diagnostic | undefined; + else { parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = d => diagnostic = d; - const parsed = getParsedCommandLineOfConfigFile(configFilePath, baseCompilerOptions, parseConfigFileHost, extendedConfigCache); + parsed = getParsedCommandLineOfConfigFile(configFileName, baseCompilerOptions, parseConfigFileHost, extendedConfigCache); parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = noop; - configFileCache.setValue(configFilePath, parsed || diagnostic!); - return parsed; + } + configFileCache.set(configFilePath, parsed || diagnostic!); + return parsed; + } + + function resolveProjectName(state: SolutionBuilderState, name: string): ResolvedConfigFileName { + return resolveConfigFileProjectName(resolvePath(state.currentDirectory, name)); + } + + function createBuildOrder(state: SolutionBuilderState, roots: readonly ResolvedConfigFileName[]): readonly ResolvedConfigFileName[] { + const temporaryMarks = createMap() as ConfigFileMap; + const permanentMarks = createMap() as ConfigFileMap; + const circularityReportStack: string[] = []; + let buildOrder: ResolvedConfigFileName[] | undefined; + for (const root of roots) { + visit(root); } - function reportStatus(message: DiagnosticMessage, ...args: string[]) { - host.reportSolutionBuilderStatus(createCompilerDiagnostic(message, ...args)); - } + return buildOrder || emptyArray; - function reportWatchStatus(message: DiagnosticMessage, ...args: (string | number | undefined)[]) { - if (hostWithWatch.onWatchStatusChange) { - hostWithWatch.onWatchStatusChange(createCompilerDiagnostic(message, ...args), host.getNewLine(), baseCompilerOptions); + function visit(configFileName: ResolvedConfigFileName, inCircularContext?: boolean) { + const projPath = toResolvedConfigFilePath(state, configFileName); + // Already visited + if (permanentMarks.has(projPath)) return; + // Circular + if (temporaryMarks.has(projPath)) { + if (!inCircularContext) { + // TODO:: Do we report this as error? + reportStatus(state, Diagnostics.Project_references_may_not_form_a_circular_graph_Cycle_detected_Colon_0, circularityReportStack.join("\r\n")); + } + return; } - } - function startWatching() { - const graph = getGlobalDependencyGraph(); - for (const resolved of graph.buildQueue) { - // Watch this file - watchConfigFile(resolved); - - const cfg = parseConfigFile(resolved); - if (cfg) { - // Update watchers for wildcard directories - watchWildCardDirectories(resolved, cfg); - - // Watch input files - watchInputFiles(resolved, cfg); + temporaryMarks.set(projPath, true); + circularityReportStack.push(configFileName); + const parsed = parseConfigFile(state, configFileName, projPath); + if (parsed && parsed.projectReferences) { + for (const ref of parsed.projectReferences) { + const resolvedRefPath = resolveProjectName(state, ref.path); + visit(resolvedRefPath, inCircularContext || ref.circular); } } + circularityReportStack.pop(); + permanentMarks.set(projPath, true); + (buildOrder || (buildOrder = [])).push(configFileName); } + } - function watchConfigFile(resolved: ResolvedConfigFileName) { - if (options.watch && !allWatchedConfigFiles.hasKey(resolved)) { - allWatchedConfigFiles.setValue(resolved, watchFile( - hostWithWatch, - resolved, - () => { - invalidateProjectAndScheduleBuilds(resolved, ConfigFileProgramReloadLevel.Full); - }, - PollingInterval.High, - WatchType.ConfigFile, - resolved - )); - } - } + function getBuildOrder(state: SolutionBuilderState) { + return state.buildOrder || + (state.buildOrder = createBuildOrder(state, state.rootNames.map(f => resolveProjectName(state, f)))); + } - function watchWildCardDirectories(resolved: ResolvedConfigFileName, parsed: ParsedCommandLine) { - if (!options.watch) return; - updateWatchingWildcardDirectories( - getOrCreateValueMapFromConfigFileMap(allWatchedWildcardDirectories, resolved), - createMapFromTemplate(parsed.configFileSpecs!.wildcardDirectories), - (dir, flags) => { - return watchDirectory( - hostWithWatch, - dir, - fileOrDirectory => { - const fileOrDirectoryPath = toPath(fileOrDirectory); - if (fileOrDirectoryPath !== toPath(dir) && hasExtension(fileOrDirectoryPath) && !isSupportedSourceFileName(fileOrDirectory, parsed.options)) { - writeLog(`Project: ${resolved} Detected file add/remove of non supported extension: ${fileOrDirectory}`); - return; - } - - if (isOutputFile(fileOrDirectory, parsed)) { - writeLog(`${fileOrDirectory} is output file`); - return; - } - - invalidateProjectAndScheduleBuilds(resolved, ConfigFileProgramReloadLevel.Partial); - }, - flags, - WatchType.WildcardDirectory, - resolved - ); - } + function getBuildOrderFor(state: SolutionBuilderState, project: string | undefined, onlyReferences: boolean | undefined) { + const resolvedProject = project && resolveProjectName(state, project); + const buildOrderFromState = getBuildOrder(state); + if (resolvedProject) { + const projectPath = toResolvedConfigFilePath(state, resolvedProject); + const projectIndex = findIndex( + buildOrderFromState, + configFileName => toResolvedConfigFilePath(state, configFileName) === projectPath ); + if (projectIndex === -1) return undefined; + } + const buildOrder = resolvedProject ? createBuildOrder(state, [resolvedProject]) : buildOrderFromState; + Debug.assert(!onlyReferences || resolvedProject !== undefined); + Debug.assert(!onlyReferences || buildOrder[buildOrder.length - 1] === resolvedProject); + return onlyReferences ? buildOrder.slice(0, buildOrder.length - 1) : buildOrder; + } + + function enableCache(state: SolutionBuilderState) { + if (state.cache) { + disableCache(state); } - function watchInputFiles(resolved: ResolvedConfigFileName, parsed: ParsedCommandLine) { - if (!options.watch) return; - mutateMap( - getOrCreateValueMapFromConfigFileMap(allWatchedInputFiles, resolved), - arrayToMap(parsed.fileNames, toPath), - { - createNewValue: (path, input) => watchFilePath( - hostWithWatch, - input, - () => invalidateProjectAndScheduleBuilds(resolved, ConfigFileProgramReloadLevel.None), - PollingInterval.Low, - path as Path, - WatchType.SourceFile, - resolved + const { compilerHost, host } = state; + + const originalReadFileWithCache = state.readFileWithCache; + const originalGetSourceFile = compilerHost.getSourceFile; + + const { + originalReadFile, originalFileExists, originalDirectoryExists, + originalCreateDirectory, originalWriteFile, + getSourceFileWithCache, readFileWithCache + } = changeCompilerHostLikeToUseCache( + host, + fileName => toPath(state, fileName), + (...args) => originalGetSourceFile.call(compilerHost, ...args) + ); + state.readFileWithCache = readFileWithCache; + compilerHost.getSourceFile = getSourceFileWithCache!; + + state.cache = { + originalReadFile, + originalFileExists, + originalDirectoryExists, + originalCreateDirectory, + originalWriteFile, + originalReadFileWithCache, + originalGetSourceFile, + }; + } + + function disableCache(state: SolutionBuilderState) { + if (!state.cache) return; + + const { cache, host, compilerHost, extendedConfigCache, moduleResolutionCache } = state; + + host.readFile = cache.originalReadFile; + host.fileExists = cache.originalFileExists; + host.directoryExists = cache.originalDirectoryExists; + host.createDirectory = cache.originalCreateDirectory; + host.writeFile = cache.originalWriteFile; + compilerHost.getSourceFile = cache.originalGetSourceFile; + state.readFileWithCache = cache.originalReadFileWithCache; + extendedConfigCache.clear(); + if (moduleResolutionCache) { + moduleResolutionCache.directoryToModuleNameMap.clear(); + moduleResolutionCache.moduleNameToDirectoryMap.clear(); + } + state.cache = undefined; + } + + function clearProjectStatus(state: SolutionBuilderState, resolved: ResolvedConfigFilePath) { + state.projectStatus.delete(resolved); + state.diagnostics.delete(resolved); + } + + function addProjToQueue({ projectPendingBuild }: SolutionBuilderState, proj: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { + const value = projectPendingBuild.get(proj); + if (value === undefined) { + projectPendingBuild.set(proj, reloadLevel); + } + else if (value < reloadLevel) { + projectPendingBuild.set(proj, reloadLevel); + } + } + + function setupInitialBuild(state: SolutionBuilderState, cancellationToken: CancellationToken | undefined) { + // Set initial build if not already built + if (!state.allProjectBuildPending) return; + state.allProjectBuildPending = false; + if (state.options.watch) { reportWatchStatus(state, Diagnostics.Starting_compilation_in_watch_mode); } + enableCache(state); + const buildOrder = getBuildOrder(state); + buildOrder.forEach(configFileName => + state.projectPendingBuild.set( + toResolvedConfigFilePath(state, configFileName), + ConfigFileProgramReloadLevel.None + ) + ); + + if (cancellationToken) { + cancellationToken.throwIfCancellationRequested(); + } + } + + export enum InvalidatedProjectKind { + Build, + UpdateBundle, + UpdateOutputFileStamps + } + + export interface InvalidatedProjectBase { + readonly kind: InvalidatedProjectKind; + readonly project: ResolvedConfigFileName; + /*@internal*/ readonly projectPath: ResolvedConfigFilePath; + /*@internal*/ readonly buildOrder: readonly ResolvedConfigFileName[]; + /** + * To dispose this project and ensure that all the necessary actions are taken and state is updated accordingly + */ + done(cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, customTransformers?: CustomTransformers): ExitStatus; + getCompilerOptions(): CompilerOptions; + getCurrentDirectory(): string; + } + + export interface UpdateOutputFileStampsProject extends InvalidatedProjectBase { + readonly kind: InvalidatedProjectKind.UpdateOutputFileStamps; + updateOutputFileStatmps(): void; + } + + export interface BuildInvalidedProject extends InvalidatedProjectBase { + readonly kind: InvalidatedProjectKind.Build; + /* + * Emitting with this builder program without the api provided for this project + * can result in build system going into invalid state as files written reflect the state of the project + */ + getBuilderProgram(): T | undefined; + getProgram(): Program | undefined; + getSourceFile(fileName: string): SourceFile | undefined; + getSourceFiles(): ReadonlyArray; + getOptionsDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray; + getGlobalDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray; + getConfigFileParsingDiagnostics(): ReadonlyArray; + getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray; + getAllDependencies(sourceFile: SourceFile): ReadonlyArray; + getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray; + getSemanticDiagnosticsOfNextAffectedFile(cancellationToken?: CancellationToken, ignoreSourceFile?: (sourceFile: SourceFile) => boolean): AffectedFileResult>; + /* + * Calling emit directly with targetSourceFile and emitOnlyDtsFiles set to true is not advised since + * emit in build system is responsible in updating status of the project + * If called with targetSourceFile and emitOnlyDtsFiles set to true, the emit just passes to underlying builder and + * wont reflect the status of file as being emitted in the builder + * (if that emit of that source file is required it would be emitted again when making sure invalidated project is completed) + * This emit is not considered actual emit (and hence uptodate status is not reflected if + */ + emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult | undefined; + // TODO(shkamat):: investigate later if we can emit even when there are declaration diagnostics + // emitNextAffectedFile(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, customTransformers?: CustomTransformers): AffectedFileResult; + } + + export interface UpdateBundleProject extends InvalidatedProjectBase { + readonly kind: InvalidatedProjectKind.UpdateBundle; + emit(writeFile?: WriteFileCallback, customTransformers?: CustomTransformers): EmitResult | BuildInvalidedProject | undefined; + } + + export type InvalidatedProject = UpdateOutputFileStampsProject | BuildInvalidedProject | UpdateBundleProject; + + function doneInvalidatedProject( + state: SolutionBuilderState, + projectPath: ResolvedConfigFilePath + ) { + state.projectPendingBuild.delete(projectPath); + state.currentInvalidatedProject = undefined; + return state.diagnostics.has(projectPath) ? + ExitStatus.DiagnosticsPresent_OutputsSkipped : + ExitStatus.Success; + } + + function createUpdateOutputFileStampsProject( + state: SolutionBuilderState, + project: ResolvedConfigFileName, + projectPath: ResolvedConfigFilePath, + config: ParsedCommandLine, + buildOrder: readonly ResolvedConfigFileName[] + ): UpdateOutputFileStampsProject { + let updateOutputFileStampsPending = true; + return { + kind: InvalidatedProjectKind.UpdateOutputFileStamps, + project, + projectPath, + buildOrder, + getCompilerOptions: () => config.options, + getCurrentDirectory: () => state.currentDirectory, + updateOutputFileStatmps: () => { + updateOutputTimestamps(state, config, projectPath); + updateOutputFileStampsPending = false; + }, + done: () => { + if (updateOutputFileStampsPending) { + updateOutputTimestamps(state, config, projectPath); + } + return doneInvalidatedProject(state, projectPath); + } + }; + } + + function createBuildOrUpdateInvalidedProject( + kind: InvalidatedProjectKind.Build | InvalidatedProjectKind.UpdateBundle, + state: SolutionBuilderState, + project: ResolvedConfigFileName, + projectPath: ResolvedConfigFilePath, + projectIndex: number, + config: ParsedCommandLine, + buildOrder: readonly ResolvedConfigFileName[], + ): BuildInvalidedProject | UpdateBundleProject { + enum Step { + CreateProgram, + SyntaxDiagnostics, + SemanticDiagnostics, + Emit, + EmitBundle, + BuildInvalidatedProjectOfBundle, + QueueReferencingProjects, + Done + } + + let step = kind === InvalidatedProjectKind.Build ? Step.CreateProgram : Step.EmitBundle; + let program: T | undefined; + let buildResult: BuildResultFlags | undefined; + let invalidatedProjectOfBundle: BuildInvalidedProject | undefined; + + return kind === InvalidatedProjectKind.Build ? + { + kind, + project, + projectPath, + buildOrder, + getCompilerOptions: () => config.options, + getCurrentDirectory: () => state.currentDirectory, + getBuilderProgram: () => withProgramOrUndefined(identity), + getProgram: () => + withProgramOrUndefined( + program => program.getProgramOrUndefined() ), - onDeleteValue: closeFileWatcher, - } + getSourceFile: fileName => + withProgramOrUndefined( + program => program.getSourceFile(fileName) + ), + getSourceFiles: () => + withProgramOrEmptyArray( + program => program.getSourceFiles() + ), + getOptionsDiagnostics: cancellationToken => + withProgramOrEmptyArray( + program => program.getOptionsDiagnostics(cancellationToken) + ), + getGlobalDiagnostics: cancellationToken => + withProgramOrEmptyArray( + program => program.getGlobalDiagnostics(cancellationToken) + ), + getConfigFileParsingDiagnostics: () => + withProgramOrEmptyArray( + program => program.getConfigFileParsingDiagnostics() + ), + getSyntacticDiagnostics: (sourceFile, cancellationToken) => + withProgramOrEmptyArray( + program => program.getSyntacticDiagnostics(sourceFile, cancellationToken) + ), + getAllDependencies: sourceFile => + withProgramOrEmptyArray( + program => program.getAllDependencies(sourceFile) + ), + getSemanticDiagnostics: (sourceFile, cancellationToken) => + withProgramOrEmptyArray( + program => program.getSemanticDiagnostics(sourceFile, cancellationToken) + ), + getSemanticDiagnosticsOfNextAffectedFile: (cancellationToken, ignoreSourceFile) => + withProgramOrUndefined( + program => + ((program as any as SemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile) && + (program as any as SemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile(cancellationToken, ignoreSourceFile) + ), + emit: (targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers) => { + if (targetSourceFile || emitOnlyDtsFiles) { + return withProgramOrUndefined( + program => program.emit(targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers) + ); + } + executeSteps(Step.SemanticDiagnostics, cancellationToken); + if (step !== Step.Emit) return undefined; + return emit(writeFile, cancellationToken, customTransformers); + }, + done + } : + { + kind, + project, + projectPath, + buildOrder, + getCompilerOptions: () => config.options, + getCurrentDirectory: () => state.currentDirectory, + emit: (writeFile: WriteFileCallback | undefined, customTransformers: CustomTransformers | undefined) => { + if (step !== Step.EmitBundle) return invalidatedProjectOfBundle; + return emitBundle(writeFile, customTransformers); + }, + done, + }; + + function done(cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, customTransformers?: CustomTransformers) { + executeSteps(Step.Done, cancellationToken, writeFile, customTransformers); + return doneInvalidatedProject(state, projectPath); + } + + function withProgramOrUndefined(action: (program: T) => U | undefined): U | undefined { + executeSteps(Step.CreateProgram); + return program && action(program); + } + + function withProgramOrEmptyArray(action: (program: T) => ReadonlyArray): ReadonlyArray { + return withProgramOrUndefined(action) || emptyArray; + } + + function createProgram() { + Debug.assert(program === undefined); + + if (state.options.dry) { + reportStatus(state, Diagnostics.A_non_dry_build_would_build_project_0, project); + buildResult = BuildResultFlags.Success; + step = Step.QueueReferencingProjects; + return; + } + + if (state.options.verbose) reportStatus(state, Diagnostics.Building_project_0, project); + + if (config.fileNames.length === 0) { + reportAndStoreErrors(state, projectPath, config.errors); + // Nothing to build - must be a solution file, basically + buildResult = BuildResultFlags.None; + step = Step.QueueReferencingProjects; + return; + } + + const { host, compilerHost } = state; + state.projectCompilerOptions = config.options; + // Update module resolution cache if needed + updateModuleResolutionCache(state, project, config); + + // Create program + program = host.createProgram( + config.fileNames, + config.options, + compilerHost, + getOldProgram(state, projectPath, config), + config.errors, + config.projectReferences ); + step++; } - function isOutputFile(fileName: string, configFile: ParsedCommandLine) { - if (configFile.options.noEmit) return false; - - // ts or tsx files are not output - if (!fileExtensionIs(fileName, Extension.Dts) && - (fileExtensionIs(fileName, Extension.Ts) || fileExtensionIs(fileName, Extension.Tsx))) { - return false; - } - - // If options have --outFile or --out, check if its that - const out = configFile.options.outFile || configFile.options.out; - if (out && (isSameFile(fileName, out) || isSameFile(fileName, removeFileExtension(out) + Extension.Dts))) { - return true; - } - - // If declarationDir is specified, return if its a file in that directory - if (configFile.options.declarationDir && containsPath(configFile.options.declarationDir, fileName, currentDirectory, !host.useCaseSensitiveFileNames())) { - return true; - } - - // If --outDir, check if file is in that directory - if (configFile.options.outDir && containsPath(configFile.options.outDir, fileName, currentDirectory, !host.useCaseSensitiveFileNames())) { - return true; - } - - return !forEach(configFile.fileNames, inputFile => isSameFile(fileName, inputFile)); - } - - function isSameFile(file1: string, file2: string) { - return comparePaths(file1, file2, currentDirectory, !host.useCaseSensitiveFileNames()) === Comparison.EqualTo; - } - - function invalidateProjectAndScheduleBuilds(resolved: ResolvedConfigFileName, reloadLevel: ConfigFileProgramReloadLevel) { - reportFileChangeDetected = true; - invalidateResolvedProject(resolved, reloadLevel); - scheduleBuildInvalidatedProject(); - } - - function getUpToDateStatusOfFile(configFileName: ResolvedConfigFileName): UpToDateStatus { - return getUpToDateStatus(parseConfigFile(configFileName)); - } - - function getBuildGraph(configFileNames: ReadonlyArray) { - return createDependencyGraph(resolveProjectNames(configFileNames)); - } - - function getGlobalDependencyGraph() { - return globalDependencyGraph || (globalDependencyGraph = getBuildGraph(rootNames)); - } - - function getUpToDateStatus(project: ParsedCommandLine | undefined): UpToDateStatus { - if (project === undefined) { - return { type: UpToDateStatusType.Unbuildable, reason: "File deleted mid-build" }; - } - - const prior = projectStatus.getValue(project.options.configFilePath as ResolvedConfigFilePath); - if (prior !== undefined) { - return prior; - } - - const actual = getUpToDateStatusWorker(project); - projectStatus.setValue(project.options.configFilePath as ResolvedConfigFilePath, actual); - return actual; - } - - function getUpToDateStatusWorker(project: ParsedCommandLine): UpToDateStatus { - let newestInputFileName: string = undefined!; - let newestInputFileTime = minimumDate; - // Get timestamps of input files - for (const inputFile of project.fileNames) { - if (!host.fileExists(inputFile)) { - return { - type: UpToDateStatusType.Unbuildable, - reason: `${inputFile} does not exist` - }; - } - - const inputTime = host.getModifiedTime(inputFile) || missingFileModifiedTime; - if (inputTime > newestInputFileTime) { - newestInputFileName = inputFile; - newestInputFileTime = inputTime; - } - } - - // Container if no files are specified in the project - if (!project.fileNames.length && !canJsonReportNoInutFiles(project.raw)) { - return { - type: UpToDateStatusType.ContainerOnly - }; - } - - // Collect the expected outputs of this project - const outputs = getAllProjectOutputs(project, !host.useCaseSensitiveFileNames()); - - // Now see if all outputs are newer than the newest input - let oldestOutputFileName = "(none)"; - let oldestOutputFileTime = maximumDate; - let newestOutputFileName = "(none)"; - let newestOutputFileTime = minimumDate; - let missingOutputFileName: string | undefined; - let newestDeclarationFileContentChangedTime = minimumDate; - let isOutOfDateWithInputs = false; - for (const output of outputs) { - // Output is missing; can stop checking - // Don't immediately return because we can still be upstream-blocked, which is a higher-priority status - if (!host.fileExists(output)) { - missingOutputFileName = output; - break; - } - - const outputTime = host.getModifiedTime(output) || missingFileModifiedTime; - if (outputTime < oldestOutputFileTime) { - oldestOutputFileTime = outputTime; - oldestOutputFileName = output; - } - - // If an output is older than the newest input, we can stop checking - // Don't immediately return because we can still be upstream-blocked, which is a higher-priority status - if (outputTime < newestInputFileTime) { - isOutOfDateWithInputs = true; - break; - } - - if (outputTime > newestOutputFileTime) { - newestOutputFileTime = outputTime; - newestOutputFileName = output; - } - - // Keep track of when the most recent time a .d.ts file was changed. - // In addition to file timestamps, we also keep track of when a .d.ts file - // had its file touched but not had its contents changed - this allows us - // to skip a downstream typecheck - if (isDeclarationFile(output)) { - const unchangedTime = unchangedOutputs.getValue(output); - if (unchangedTime !== undefined) { - newestDeclarationFileContentChangedTime = newer(unchangedTime, newestDeclarationFileContentChangedTime); - } - else { - const outputModifiedTime = host.getModifiedTime(output) || missingFileModifiedTime; - newestDeclarationFileContentChangedTime = newer(newestDeclarationFileContentChangedTime, outputModifiedTime); - } - } - } - - let pseudoUpToDate = false; - let usesPrepend = false; - let upstreamChangedProject: string | undefined; - if (project.projectReferences) { - projectStatus.setValue(project.options.configFilePath as ResolvedConfigFileName, { type: UpToDateStatusType.ComputingUpstream }); - for (const ref of project.projectReferences) { - usesPrepend = usesPrepend || !!(ref.prepend); - const resolvedRef = resolveProjectReferencePath(ref); - const refStatus = getUpToDateStatus(parseConfigFile(resolvedRef)); - - // Its a circular reference ignore the status of this project - if (refStatus.type === UpToDateStatusType.ComputingUpstream) { - continue; - } - - // An upstream project is blocked - if (refStatus.type === UpToDateStatusType.Unbuildable) { - return { - type: UpToDateStatusType.UpstreamBlocked, - upstreamProjectName: ref.path - }; - } - - // If the upstream project is out of date, then so are we (someone shouldn't have asked, though?) - if (refStatus.type !== UpToDateStatusType.UpToDate) { - return { - type: UpToDateStatusType.UpstreamOutOfDate, - upstreamProjectName: ref.path - }; - } - - // Check oldest output file name only if there is no missing output file name - if (!missingOutputFileName) { - // If the upstream project's newest file is older than our oldest output, we - // can't be out of date because of it - if (refStatus.newestInputFileTime && refStatus.newestInputFileTime <= oldestOutputFileTime) { - continue; - } - - // If the upstream project has only change .d.ts files, and we've built - // *after* those files, then we're "psuedo up to date" and eligible for a fast rebuild - if (refStatus.newestDeclarationFileContentChangedTime && refStatus.newestDeclarationFileContentChangedTime <= oldestOutputFileTime) { - pseudoUpToDate = true; - upstreamChangedProject = ref.path; - continue; - } - - // We have an output older than an upstream output - we are out of date - Debug.assert(oldestOutputFileName !== undefined, "Should have an oldest output filename here"); - return { - type: UpToDateStatusType.OutOfDateWithUpstream, - outOfDateOutputFileName: oldestOutputFileName, - newerProjectName: ref.path - }; - } - } - } - - if (missingOutputFileName !== undefined) { - return { - type: UpToDateStatusType.OutputMissing, - missingOutputFileName - }; - } - - if (isOutOfDateWithInputs) { - return { - type: UpToDateStatusType.OutOfDateWithSelf, - outOfDateOutputFileName: oldestOutputFileName, - newerInputFileName: newestInputFileName - }; + function handleDiagnostics(diagnostics: ReadonlyArray, errorFlags: BuildResultFlags, errorType: string) { + if (diagnostics.length) { + buildResult = buildErrors( + state, + projectPath, + program, + diagnostics, + errorFlags, + errorType + ); + step = Step.QueueReferencingProjects; } else { - // Check tsconfig time - const configStatus = checkConfigFileUpToDateStatus(project.options.configFilePath!, oldestOutputFileTime, oldestOutputFileName); - if (configStatus) return configStatus; - - // Check extended config time - const extendedConfigStatus = forEach(project.options.configFile!.extendedSourceFiles || emptyArray, configFile => checkConfigFileUpToDateStatus(configFile, oldestOutputFileTime, oldestOutputFileName)); - if (extendedConfigStatus) return extendedConfigStatus; - } - - if (!buildInfoChecked.hasKey(project.options.configFilePath as ResolvedConfigFileName)) { - buildInfoChecked.setValue(project.options.configFilePath as ResolvedConfigFileName, true); - const buildInfoPath = getOutputPathForBuildInfo(project.options); - if (buildInfoPath) { - const value = readFileWithCache(buildInfoPath); - const buildInfo = value && getBuildInfo(value); - if (buildInfo && buildInfo.version !== version) { - return { - type: UpToDateStatusType.TsVersionOutputOfDate, - version: buildInfo.version - }; - } - } - } - - if (usesPrepend && pseudoUpToDate) { - return { - type: UpToDateStatusType.OutOfDateWithPrepend, - outOfDateOutputFileName: oldestOutputFileName, - newerProjectName: upstreamChangedProject! - }; - } - - // Up to date - return { - type: pseudoUpToDate ? UpToDateStatusType.UpToDateWithUpstreamTypes : UpToDateStatusType.UpToDate, - newestDeclarationFileContentChangedTime, - newestInputFileTime, - newestOutputFileTime, - newestInputFileName, - newestOutputFileName, - oldestOutputFileName - }; - } - - function checkConfigFileUpToDateStatus(configFile: string, oldestOutputFileTime: Date, oldestOutputFileName: string): Status.OutOfDateWithSelf | undefined { - // Check tsconfig time - const tsconfigTime = host.getModifiedTime(configFile) || missingFileModifiedTime; - if (oldestOutputFileTime < tsconfigTime) { - return { - type: UpToDateStatusType.OutOfDateWithSelf, - outOfDateOutputFileName: oldestOutputFileName, - newerInputFileName: configFile - }; + step++; } } - function invalidateProject(configFileName: string, reloadLevel?: ConfigFileProgramReloadLevel) { - invalidateResolvedProject(resolveProjectName(configFileName), reloadLevel); - } - - function invalidateResolvedProject(resolved: ResolvedConfigFileName, reloadLevel?: ConfigFileProgramReloadLevel) { - if (reloadLevel === ConfigFileProgramReloadLevel.Full) { - configFileCache.removeKey(resolved); - globalDependencyGraph = undefined; - } - projectStatus.removeKey(resolved); - diagnostics.removeKey(resolved); - - addProjToQueue(resolved, reloadLevel); - enableCache(); - } - - /** - * return true if new addition - */ - function addProjToQueue(proj: ResolvedConfigFileName, reloadLevel?: ConfigFileProgramReloadLevel) { - const value = projectPendingBuild.getValue(proj); - if (value === undefined) { - projectPendingBuild.setValue(proj, reloadLevel || ConfigFileProgramReloadLevel.None); - invalidatedProjectQueue.push(proj); - } - else if (value < (reloadLevel || ConfigFileProgramReloadLevel.None)) { - projectPendingBuild.setValue(proj, reloadLevel || ConfigFileProgramReloadLevel.None); - } - } - - function getNextInvalidatedProject() { - if (nextProjectToBuild < invalidatedProjectQueue.length) { - const project = invalidatedProjectQueue[nextProjectToBuild]; - nextProjectToBuild++; - const reloadLevel = projectPendingBuild.getValue(project)!; - projectPendingBuild.removeKey(project); - if (!projectPendingBuild.getSize()) { - invalidatedProjectQueue.length = 0; - nextProjectToBuild = 0; - } - return { project, reloadLevel }; - } - } - - function hasPendingInvalidatedProjects() { - return !!projectPendingBuild.getSize(); - } - - function scheduleBuildInvalidatedProject() { - if (!hostWithWatch.setTimeout || !hostWithWatch.clearTimeout) { - return; - } - if (timerToBuildInvalidatedProject) { - hostWithWatch.clearTimeout(timerToBuildInvalidatedProject); - } - timerToBuildInvalidatedProject = hostWithWatch.setTimeout(buildInvalidatedProject, 250); - } - - function buildInvalidatedProject() { - timerToBuildInvalidatedProject = undefined; - if (reportFileChangeDetected) { - reportFileChangeDetected = false; - projectErrorsReported.clear(); - reportWatchStatus(Diagnostics.File_change_detected_Starting_incremental_compilation); - } - const buildProject = getNextInvalidatedProject(); - if (buildProject) { - buildSingleInvalidatedProject(buildProject.project, buildProject.reloadLevel); - if (hasPendingInvalidatedProjects()) { - if (options.watch && !timerToBuildInvalidatedProject) { - scheduleBuildInvalidatedProject(); - } - } - else { - disableCache(); - reportErrorSummary(); - } - } - } - - function reportErrorSummary() { - if (options.watch || (host as SolutionBuilderHost).reportErrorSummary) { - // Report errors from the other projects - getGlobalDependencyGraph().buildQueue.forEach(project => { - if (!projectErrorsReported.hasKey(project)) { - reportErrors(diagnostics.getValue(project) || emptyArray); - } - }); - let totalErrors = 0; - diagnostics.forEach(singleProjectErrors => totalErrors += getErrorCountForSummary(singleProjectErrors)); - if (options.watch) { - reportWatchStatus(getWatchErrorSummaryDiagnosticMessage(totalErrors), totalErrors); - } - else { - (host as SolutionBuilderHost).reportErrorSummary!(totalErrors); - } - } - } - - function buildSingleInvalidatedProject(resolved: ResolvedConfigFileName, reloadLevel: ConfigFileProgramReloadLevel) { - const proj = parseConfigFile(resolved); - if (!proj) { - reportParseConfigFileDiagnostic(resolved); - return; - } - - if (reloadLevel === ConfigFileProgramReloadLevel.Full) { - watchConfigFile(resolved); - watchWildCardDirectories(resolved, proj); - watchInputFiles(resolved, proj); - } - else if (reloadLevel === ConfigFileProgramReloadLevel.Partial) { - // Update file names - const result = getFileNamesFromConfigSpecs(proj.configFileSpecs!, getDirectoryPath(resolved), proj.options, parseConfigFileHost); - updateErrorForNoInputFiles(result, resolved, proj.configFileSpecs!, proj.errors, canJsonReportNoInutFiles(proj.raw)); - proj.fileNames = result.fileNames; - watchInputFiles(resolved, proj); - } - - const status = getUpToDateStatus(proj); - verboseReportProjectStatus(resolved, status); - - if (status.type === UpToDateStatusType.UpstreamBlocked) { - if (options.verbose) reportStatus(Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_has_errors, resolved, status.upstreamProjectName); - return; - } - - if (status.type === UpToDateStatusType.UpToDateWithUpstreamTypes) { - // Fake that files have been built by updating output file stamps - updateOutputTimestamps(proj); - return; - } - - const buildResult = needsBuild(status, resolved) ? - buildSingleProject(resolved) : // Actual build - updateBundle(resolved); // Fake that files have been built by manipulating prepend and existing output - if (buildResult & BuildResultFlags.AnyErrors) return; - - const { referencingProjectsMap, buildQueue } = getGlobalDependencyGraph(); - const referencingProjects = referencingProjectsMap.getValue(resolved); - if (!referencingProjects) return; - - // Always use build order to queue projects - for (let index = buildQueue.indexOf(resolved) + 1; index < buildQueue.length; index++) { - const project = buildQueue[index]; - const prepend = referencingProjects.getValue(project); - if (prepend !== undefined) { - // If the project is referenced with prepend, always build downstream projects, - // If declaration output is changed, build the project - // otherwise mark the project UpToDateWithUpstreamTypes so it updates output time stamps - const status = projectStatus.getValue(project); - if (!(buildResult & BuildResultFlags.DeclarationOutputUnchanged)) { - if (status && (status.type === UpToDateStatusType.UpToDate || status.type === UpToDateStatusType.UpToDateWithUpstreamTypes || status.type === UpToDateStatusType.OutOfDateWithPrepend)) { - projectStatus.setValue(project, { - type: UpToDateStatusType.OutOfDateWithUpstream, - outOfDateOutputFileName: status.type === UpToDateStatusType.OutOfDateWithPrepend ? status.outOfDateOutputFileName : status.oldestOutputFileName, - newerProjectName: resolved - }); - } - } - else if (status && status.type === UpToDateStatusType.UpToDate) { - if (prepend) { - projectStatus.setValue(project, { - type: UpToDateStatusType.OutOfDateWithPrepend, - outOfDateOutputFileName: status.oldestOutputFileName, - newerProjectName: resolved - }); - } - else { - status.type = UpToDateStatusType.UpToDateWithUpstreamTypes; - } - } - addProjToQueue(project); - } - } - } - - function createDependencyGraph(roots: ResolvedConfigFileName[]): DependencyGraph { - const temporaryMarks = createFileMap(toPath); - const permanentMarks = createFileMap(toPath); - const circularityReportStack: string[] = []; - const buildOrder: ResolvedConfigFileName[] = []; - const referencingProjectsMap = createFileMap>(toPath); - for (const root of roots) { - visit(root); - } - - return { - buildQueue: buildOrder, - referencingProjectsMap - }; - - function visit(projPath: ResolvedConfigFileName, inCircularContext?: boolean) { - // Already visited - if (permanentMarks.hasKey(projPath)) return; - // Circular - if (temporaryMarks.hasKey(projPath)) { - if (!inCircularContext) { - // TODO:: Do we report this as error? - reportStatus(Diagnostics.Project_references_may_not_form_a_circular_graph_Cycle_detected_Colon_0, circularityReportStack.join("\r\n")); - } - return; - } - - temporaryMarks.setValue(projPath, true); - circularityReportStack.push(projPath); - const parsed = parseConfigFile(projPath); - if (parsed && parsed.projectReferences) { - for (const ref of parsed.projectReferences) { - const resolvedRefPath = resolveProjectName(ref.path); - visit(resolvedRefPath, inCircularContext || ref.circular); - // Get projects referencing resolvedRefPath and add projPath to it - const referencingProjects = getOrCreateValueFromConfigFileMap(referencingProjectsMap, resolvedRefPath, () => createFileMap(toPath)); - referencingProjects.setValue(projPath, !!ref.prepend); - } - } - - circularityReportStack.pop(); - permanentMarks.setValue(projPath, true); - buildOrder.push(projPath); - } - } - - function buildSingleProject(proj: ResolvedConfigFileName): BuildResultFlags { - if (options.dry) { - reportStatus(Diagnostics.A_non_dry_build_would_build_project_0, proj); - return BuildResultFlags.Success; - } - - if (options.verbose) reportStatus(Diagnostics.Building_project_0, proj); - - let resultFlags = BuildResultFlags.DeclarationOutputUnchanged; - - const configFile = parseConfigFile(proj); - if (!configFile) { - // Failed to read the config file - resultFlags |= BuildResultFlags.ConfigFileErrors; - reportParseConfigFileDiagnostic(proj); - projectStatus.setValue(proj, { type: UpToDateStatusType.Unbuildable, reason: "Config file errors" }); - return resultFlags; - } - if (configFile.fileNames.length === 0) { - reportAndStoreErrors(proj, configFile.errors); - // Nothing to build - must be a solution file, basically - return BuildResultFlags.None; - } - - // TODO: handle resolve module name to cache result in project reference redirect - projectCompilerOptions = configFile.options; - // Update module resolution cache if needed - if (moduleResolutionCache) { - const projPath = toPath(proj); - if (moduleResolutionCache.directoryToModuleNameMap.redirectsMap.size === 0) { - // The own map will be for projectCompilerOptions - Debug.assert(moduleResolutionCache.moduleNameToDirectoryMap.redirectsMap.size === 0); - moduleResolutionCache.directoryToModuleNameMap.redirectsMap.set(projPath, moduleResolutionCache.directoryToModuleNameMap.ownMap); - moduleResolutionCache.moduleNameToDirectoryMap.redirectsMap.set(projPath, moduleResolutionCache.moduleNameToDirectoryMap.ownMap); - } - else { - // Set correct own map - Debug.assert(moduleResolutionCache.moduleNameToDirectoryMap.redirectsMap.size > 0); - - const ref: ResolvedProjectReference = { - sourceFile: projectCompilerOptions.configFile!, - commandLine: configFile - }; - moduleResolutionCache.directoryToModuleNameMap.setOwnMap(moduleResolutionCache.directoryToModuleNameMap.getOrCreateMapOfCacheRedirects(ref)); - moduleResolutionCache.moduleNameToDirectoryMap.setOwnMap(moduleResolutionCache.moduleNameToDirectoryMap.getOrCreateMapOfCacheRedirects(ref)); - } - moduleResolutionCache.directoryToModuleNameMap.setOwnOptions(projectCompilerOptions); - moduleResolutionCache.moduleNameToDirectoryMap.setOwnOptions(projectCompilerOptions); - } - - const program = host.createProgram( - configFile.fileNames, - configFile.options, - compilerHost, - getOldProgram(proj, configFile), - configFile.errors, - configFile.projectReferences + function getSyntaxDiagnostics(cancellationToken?: CancellationToken) { + Debug.assertDefined(program); + handleDiagnostics( + [ + ...program!.getConfigFileParsingDiagnostics(), + ...program!.getOptionsDiagnostics(cancellationToken), + ...program!.getGlobalDiagnostics(cancellationToken), + ...program!.getSyntacticDiagnostics(/*sourceFile*/ undefined, cancellationToken) + ], + BuildResultFlags.SyntaxErrors, + "Syntactic" ); + } - // Don't emit anything in the presence of syntactic errors or options diagnostics - const syntaxDiagnostics = [ - ...program.getConfigFileParsingDiagnostics(), - ...program.getOptionsDiagnostics(), - ...program.getGlobalDiagnostics(), - ...program.getSyntacticDiagnostics()]; - if (syntaxDiagnostics.length) { - return buildErrors(syntaxDiagnostics, BuildResultFlags.SyntaxErrors, "Syntactic"); - } - - // Same as above but now for semantic diagnostics - const semanticDiagnostics = program.getSemanticDiagnostics(); - if (semanticDiagnostics.length) { - return buildErrors(semanticDiagnostics, BuildResultFlags.TypeErrors, "Semantic"); - } + function getSemanticDiagnostics(cancellationToken?: CancellationToken) { + handleDiagnostics( + Debug.assertDefined(program).getSemanticDiagnostics(/*sourceFile*/ undefined, cancellationToken), + BuildResultFlags.TypeErrors, + "Semantic" + ); + } + function emit(writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken, customTransformers?: CustomTransformers): EmitResult { + Debug.assertDefined(program); + Debug.assert(step === Step.Emit); // Before emitting lets backup state, so we can revert it back if there are declaration errors to handle emit and declaration errors correctly - program.backupState(); - let newestDeclarationFileContentChangedTime = minimumDate; - let anyDtsChanged = false; + program!.backupState(); let declDiagnostics: Diagnostic[] | undefined; const reportDeclarationDiagnostics = (d: Diagnostic) => (declDiagnostics || (declDiagnostics = [])).push(d); const outputFiles: OutputFile[] = []; - emitFilesAndReportErrors(program, reportDeclarationDiagnostics, /*writeFileName*/ undefined, /*reportSummary*/ undefined, (name, text, writeByteOrderMark) => outputFiles.push({ name, text, writeByteOrderMark })); + const { emitResult } = emitFilesAndReportErrors( + program!, + reportDeclarationDiagnostics, + /*writeFileName*/ undefined, + /*reportSummary*/ undefined, + (name, text, writeByteOrderMark) => outputFiles.push({ name, text, writeByteOrderMark }), + cancellationToken, + /*emitOnlyDts*/ false, + customTransformers + ); // Don't emit .d.ts if there are decl file errors if (declDiagnostics) { - program.restoreState(); - return buildErrors(declDiagnostics, BuildResultFlags.DeclarationEmitErrors, "Declaration file"); + program!.restoreState(); + buildResult = buildErrors( + state, + projectPath, + program, + declDiagnostics, + BuildResultFlags.DeclarationEmitErrors, + "Declaration file" + ); + step = Step.QueueReferencingProjects; + return { + emitSkipped: true, + diagnostics: emitResult.diagnostics + }; } // Actual Emit + const { host, compilerHost } = state; + let resultFlags = BuildResultFlags.DeclarationOutputUnchanged; + let newestDeclarationFileContentChangedTime = minimumDate; + let anyDtsChanged = false; const emitterDiagnostics = createDiagnosticCollection(); - const emittedOutputs = createFileMap(toPath as ToPath); + const emittedOutputs = createMap() as FileMap; outputFiles.forEach(({ name, text, writeByteOrderMark }) => { let priorChangeTime: Date | undefined; if (!anyDtsChanged && isDeclarationFile(name)) { // Check for unchanged .d.ts files - if (host.fileExists(name) && readFileWithCache(name) === text) { + if (host.fileExists(name) && state.readFileWithCache(name) === text) { priorChangeTime = host.getModifiedTime(name); } else { @@ -1194,426 +1019,1085 @@ namespace ts { } } - emittedOutputs.setValue(name, name); - writeFile(compilerHost, emitterDiagnostics, name, text, writeByteOrderMark); + emittedOutputs.set(toPath(state, name), name); + writeFile(writeFileCallback ? { writeFile: writeFileCallback } : compilerHost, emitterDiagnostics, name, text, writeByteOrderMark); if (priorChangeTime !== undefined) { newestDeclarationFileContentChangedTime = newer(priorChangeTime, newestDeclarationFileContentChangedTime); - unchangedOutputs.setValue(name, priorChangeTime); } }); + finishEmit( + emitterDiagnostics, + emittedOutputs, + newestDeclarationFileContentChangedTime, + /*newestDeclarationFileContentChangedTimeIsMaximumDate*/ anyDtsChanged, + outputFiles.length ? outputFiles[0].name : getFirstProjectOutput(config, !host.useCaseSensitiveFileNames()), + resultFlags + ); + return emitResult; + } + + function finishEmit( + emitterDiagnostics: DiagnosticCollection, + emittedOutputs: FileMap, + priorNewestUpdateTime: Date, + newestDeclarationFileContentChangedTimeIsMaximumDate: boolean, + oldestOutputFileName: string, + resultFlags: BuildResultFlags + ) { const emitDiagnostics = emitterDiagnostics.getDiagnostics(); if (emitDiagnostics.length) { - return buildErrors(emitDiagnostics, BuildResultFlags.EmitErrors, "Emit"); + buildResult = buildErrors( + state, + projectPath, + program, + emitDiagnostics, + BuildResultFlags.EmitErrors, + "Emit" + ); + step = Step.QueueReferencingProjects; + return emitDiagnostics; } - if (writeFileName) { - emittedOutputs.forEach(name => listEmittedFile(configFile, name)); - listFiles(program, writeFileName); + if (state.writeFileName) { + emittedOutputs.forEach(name => listEmittedFile(state, config, name)); + if (program) listFiles(program, state.writeFileName); } // Update time stamps for rest of the outputs - newestDeclarationFileContentChangedTime = updateOutputTimestampsWorker(configFile, newestDeclarationFileContentChangedTime, Diagnostics.Updating_unchanged_output_timestamps_of_project_0, emittedOutputs); - - const status: Status.UpToDate = { + const newestDeclarationFileContentChangedTime = updateOutputTimestampsWorker(state, config, priorNewestUpdateTime, Diagnostics.Updating_unchanged_output_timestamps_of_project_0, emittedOutputs); + state.diagnostics.delete(projectPath); + state.projectStatus.set(projectPath, { type: UpToDateStatusType.UpToDate, - newestDeclarationFileContentChangedTime: anyDtsChanged ? maximumDate : newestDeclarationFileContentChangedTime, - oldestOutputFileName: outputFiles.length ? outputFiles[0].name : getFirstProjectOutput(configFile, !host.useCaseSensitiveFileNames()) - }; - diagnostics.removeKey(proj); - projectStatus.setValue(proj, status); - afterProgramCreate(proj, program); - projectCompilerOptions = baseCompilerOptions; - return resultFlags; - - function buildErrors(diagnostics: ReadonlyArray, errorFlags: BuildResultFlags, errorType: string) { - resultFlags |= errorFlags; - reportAndStoreErrors(proj, diagnostics); - // List files if any other build error using program (emit errors already report files) - if (writeFileName) listFiles(program, writeFileName); - projectStatus.setValue(proj, { type: UpToDateStatusType.Unbuildable, reason: `${errorType} errors` }); - afterProgramCreate(proj, program); - projectCompilerOptions = baseCompilerOptions; - return resultFlags; - } + newestDeclarationFileContentChangedTime: newestDeclarationFileContentChangedTimeIsMaximumDate ? + maximumDate : + newestDeclarationFileContentChangedTime, + oldestOutputFileName + }); + if (program) afterProgramCreate(state, projectPath, program); + state.projectCompilerOptions = state.baseCompilerOptions; + step = Step.QueueReferencingProjects; + buildResult = resultFlags; + return emitDiagnostics; } - function listEmittedFile(proj: ParsedCommandLine, file: string) { - if (writeFileName && proj.options.listEmittedFiles) { - writeFileName(`TSFILE: ${file}`); - } - } - - function afterProgramCreate(proj: ResolvedConfigFileName, program: T) { - if (host.afterProgramEmitAndDiagnostics) { - host.afterProgramEmitAndDiagnostics(program); - } - if (options.watch) { - program.releaseProgram(); - builderPrograms.setValue(proj, program); - } - } - - function getOldProgram(proj: ResolvedConfigFileName, parsed: ParsedCommandLine) { - if (options.force) return undefined; - const value = builderPrograms.getValue(proj); - if (value) return value; - return readBuilderProgram(parsed.options, readFileWithCache) as any as T; - } - - function updateBundle(proj: ResolvedConfigFileName): BuildResultFlags { - if (options.dry) { - reportStatus(Diagnostics.A_non_dry_build_would_update_output_of_project_0, proj); - return BuildResultFlags.Success; + function emitBundle(writeFileCallback?: WriteFileCallback, customTransformers?: CustomTransformers): EmitResult | BuildInvalidedProject | undefined { + Debug.assert(kind === InvalidatedProjectKind.UpdateBundle); + if (state.options.dry) { + reportStatus(state, Diagnostics.A_non_dry_build_would_update_output_of_project_0, project); + buildResult = BuildResultFlags.Success; + step = Step.QueueReferencingProjects; + return undefined; } - if (options.verbose) reportStatus(Diagnostics.Updating_output_of_project_0, proj); + if (state.options.verbose) reportStatus(state, Diagnostics.Updating_output_of_project_0, project); // Update js, and source map - const config = Debug.assertDefined(parseConfigFile(proj)); - projectCompilerOptions = config.options; + const { compilerHost } = state; + state.projectCompilerOptions = config.options; const outputFiles = emitUsingBuildInfo( config, compilerHost, - ref => parseConfigFile(resolveProjectName(ref.path))); + ref => { + const refName = resolveProjectName(state, ref.path); + return parseConfigFile(state, refName, toResolvedConfigFilePath(state, refName)); + }, + customTransformers + ); + if (isString(outputFiles)) { - reportStatus(Diagnostics.Cannot_update_output_of_project_0_because_there_was_error_reading_file_1, proj, relName(outputFiles)); - return buildSingleProject(proj); + reportStatus(state, Diagnostics.Cannot_update_output_of_project_0_because_there_was_error_reading_file_1, project, relName(state, outputFiles)); + step = Step.BuildInvalidatedProjectOfBundle; + return invalidatedProjectOfBundle = createBuildOrUpdateInvalidedProject( + InvalidatedProjectKind.Build, + state, + project, + projectPath, + projectIndex, + config, + buildOrder + ) as BuildInvalidedProject; } // Actual Emit Debug.assert(!!outputFiles.length); const emitterDiagnostics = createDiagnosticCollection(); - const emittedOutputs = createFileMap(toPath as ToPath); + const emittedOutputs = createMap() as FileMap; outputFiles.forEach(({ name, text, writeByteOrderMark }) => { - emittedOutputs.setValue(name, name); - writeFile(compilerHost, emitterDiagnostics, name, text, writeByteOrderMark); + emittedOutputs.set(toPath(state, name), name); + writeFile(writeFileCallback ? { writeFile: writeFileCallback } : compilerHost, emitterDiagnostics, name, text, writeByteOrderMark); }); - const emitDiagnostics = emitterDiagnostics.getDiagnostics(); - if (emitDiagnostics.length) { - reportAndStoreErrors(proj, emitDiagnostics); - projectStatus.setValue(proj, { type: UpToDateStatusType.Unbuildable, reason: "Emit errors" }); - projectCompilerOptions = baseCompilerOptions; - return BuildResultFlags.DeclarationOutputUnchanged | BuildResultFlags.EmitErrors; - } - if (writeFileName) { - emittedOutputs.forEach(name => listEmittedFile(config, name)); - } - - // Update timestamps for dts - const newestDeclarationFileContentChangedTime = updateOutputTimestampsWorker(config, minimumDate, Diagnostics.Updating_unchanged_output_timestamps_of_project_0, emittedOutputs); - - const status: Status.UpToDate = { - type: UpToDateStatusType.UpToDate, - newestDeclarationFileContentChangedTime, - oldestOutputFileName: outputFiles[0].name - }; - - diagnostics.removeKey(proj); - projectStatus.setValue(proj, status); - projectCompilerOptions = baseCompilerOptions; - return BuildResultFlags.DeclarationOutputUnchanged; + const emitDiagnostics = finishEmit( + emitterDiagnostics, + emittedOutputs, + minimumDate, + /*newestDeclarationFileContentChangedTimeIsMaximumDate*/ false, + outputFiles[0].name, + BuildResultFlags.DeclarationOutputUnchanged + ); + return { emitSkipped: false, diagnostics: emitDiagnostics }; } - function updateOutputTimestamps(proj: ParsedCommandLine) { - if (options.dry) { - return reportStatus(Diagnostics.A_non_dry_build_would_update_timestamps_for_output_of_project_0, proj.options.configFilePath!); - } - const priorNewestUpdateTime = updateOutputTimestampsWorker(proj, minimumDate, Diagnostics.Updating_output_timestamps_of_project_0); - const status: Status.UpToDate = { - type: UpToDateStatusType.UpToDate, - newestDeclarationFileContentChangedTime: priorNewestUpdateTime, - oldestOutputFileName: getFirstProjectOutput(proj, !host.useCaseSensitiveFileNames()) - }; - projectStatus.setValue(proj.options.configFilePath as ResolvedConfigFilePath, status); - } + function executeSteps(till: Step, cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, customTransformers?: CustomTransformers) { + while (step <= till && step < Step.Done) { + const currentStep = step; + switch (step) { + case Step.CreateProgram: + createProgram(); + break; + + case Step.SyntaxDiagnostics: + getSyntaxDiagnostics(cancellationToken); + break; + + case Step.SemanticDiagnostics: + getSemanticDiagnostics(cancellationToken); + break; + + case Step.Emit: + emit(writeFile, cancellationToken, customTransformers); + break; + + case Step.EmitBundle: + emitBundle(writeFile, customTransformers); + break; + + case Step.BuildInvalidatedProjectOfBundle: + Debug.assertDefined(invalidatedProjectOfBundle).done(cancellationToken); + step = Step.Done; + break; + + case Step.QueueReferencingProjects: + queueReferencingProjects(state, project, projectPath, projectIndex, config, buildOrder, Debug.assertDefined(buildResult)); + step++; + break; + + // Should never be done + case Step.Done: + default: + assertType(step); - function updateOutputTimestampsWorker(proj: ParsedCommandLine, priorNewestUpdateTime: Date, verboseMessage: DiagnosticMessage, skipOutputs?: FileMap) { - const outputs = getAllProjectOutputs(proj, !host.useCaseSensitiveFileNames()); - if (!skipOutputs || outputs.length !== skipOutputs.getSize()) { - if (options.verbose) { - reportStatus(verboseMessage, proj.options.configFilePath!); } - const now = host.now ? host.now() : new Date(); - for (const file of outputs) { - if (skipOutputs && skipOutputs.hasKey(file)) { + Debug.assert(step > currentStep); + } + } + } + + function needsBuild({ options }: SolutionBuilderState, status: UpToDateStatus, config: ParsedCommandLine) { + if (status.type !== UpToDateStatusType.OutOfDateWithPrepend || options.force) return true; + return config.fileNames.length === 0 || + !!config.errors.length || + !isIncrementalCompilation(config.options); + } + + function getNextInvalidatedProject( + state: SolutionBuilderState, + buildOrder: readonly ResolvedConfigFileName[], + reportQueue: boolean + ): InvalidatedProject | undefined { + if (!state.projectPendingBuild.size) return undefined; + if (state.currentInvalidatedProject) { + // Only if same buildOrder the currentInvalidated project can be sent again + return arrayIsEqualTo(state.currentInvalidatedProject.buildOrder, buildOrder) ? + state.currentInvalidatedProject : + undefined; + } + + const { options, projectPendingBuild } = state; + for (let projectIndex = 0; projectIndex < buildOrder.length; projectIndex++) { + const project = buildOrder[projectIndex]; + const projectPath = toResolvedConfigFilePath(state, project); + const reloadLevel = state.projectPendingBuild.get(projectPath); + if (reloadLevel === undefined) continue; + + if (reportQueue) { + reportQueue = false; + reportBuildQueue(state, buildOrder); + } + + const config = parseConfigFile(state, project, projectPath); + if (!config) { + reportParseConfigFileDiagnostic(state, projectPath); + projectPendingBuild.delete(projectPath); + continue; + } + + if (reloadLevel === ConfigFileProgramReloadLevel.Full) { + watchConfigFile(state, project, projectPath); + watchWildCardDirectories(state, project, projectPath, config); + watchInputFiles(state, project, projectPath, config); + } + else if (reloadLevel === ConfigFileProgramReloadLevel.Partial) { + // Update file names + const result = getFileNamesFromConfigSpecs(config.configFileSpecs!, getDirectoryPath(project), config.options, state.parseConfigFileHost); + updateErrorForNoInputFiles(result, project, config.configFileSpecs!, config.errors, canJsonReportNoInutFiles(config.raw)); + config.fileNames = result.fileNames; + watchInputFiles(state, project, projectPath, config); + } + + const status = getUpToDateStatus(state, config, projectPath); + verboseReportProjectStatus(state, project, status); + if (!options.force) { + if (status.type === UpToDateStatusType.UpToDate) { + reportAndStoreErrors(state, projectPath, config.errors); + projectPendingBuild.delete(projectPath); + // Up to date, skip + if (options.dry) { + // In a dry build, inform the user of this fact + reportStatus(state, Diagnostics.Project_0_is_up_to_date, project); + } + continue; + } + + if (status.type === UpToDateStatusType.UpToDateWithUpstreamTypes) { + reportAndStoreErrors(state, projectPath, config.errors); + return createUpdateOutputFileStampsProject( + state, + project, + projectPath, + config, + buildOrder + ); + } + } + + if (status.type === UpToDateStatusType.UpstreamBlocked) { + reportAndStoreErrors(state, projectPath, config.errors); + projectPendingBuild.delete(projectPath); + if (options.verbose) reportStatus(state, Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_has_errors, project, status.upstreamProjectName); + continue; + } + + if (status.type === UpToDateStatusType.ContainerOnly) { + reportAndStoreErrors(state, projectPath, config.errors); + projectPendingBuild.delete(projectPath); + // Do nothing + continue; + } + + return createBuildOrUpdateInvalidedProject( + needsBuild(state, status, config) ? + InvalidatedProjectKind.Build : + InvalidatedProjectKind.UpdateBundle, + state, + project, + projectPath, + projectIndex, + config, + buildOrder, + ); + } + + return undefined; + } + + function listEmittedFile({ writeFileName }: SolutionBuilderState, proj: ParsedCommandLine, file: string) { + if (writeFileName && proj.options.listEmittedFiles) { + writeFileName(`TSFILE: ${file}`); + } + } + + function getOldProgram({ options, builderPrograms, readFileWithCache }: SolutionBuilderState, proj: ResolvedConfigFilePath, parsed: ParsedCommandLine) { + if (options.force) return undefined; + const value = builderPrograms.get(proj); + if (value) return value; + return readBuilderProgram(parsed.options, readFileWithCache) as any as T; + } + + function afterProgramCreate({ host, watch, builderPrograms }: SolutionBuilderState, proj: ResolvedConfigFilePath, program: T) { + if (host.afterProgramEmitAndDiagnostics) { + host.afterProgramEmitAndDiagnostics(program); + } + if (watch) { + program.releaseProgram(); + builderPrograms.set(proj, program); + } + } + + function buildErrors( + state: SolutionBuilderState, + resolvedPath: ResolvedConfigFilePath, + program: T | undefined, + diagnostics: ReadonlyArray, + errorFlags: BuildResultFlags, + errorType: string + ) { + reportAndStoreErrors(state, resolvedPath, diagnostics); + // List files if any other build error using program (emit errors already report files) + if (program && state.writeFileName) listFiles(program, state.writeFileName); + state.projectStatus.set(resolvedPath, { type: UpToDateStatusType.Unbuildable, reason: `${errorType} errors` }); + if (program) afterProgramCreate(state, resolvedPath, program); + state.projectCompilerOptions = state.baseCompilerOptions; + return errorFlags; + } + + function updateModuleResolutionCache( + state: SolutionBuilderState, + proj: ResolvedConfigFileName, + config: ParsedCommandLine + ) { + if (!state.moduleResolutionCache) return; + + // Update module resolution cache if needed + const { moduleResolutionCache } = state; + const projPath = toPath(state, proj); + if (moduleResolutionCache.directoryToModuleNameMap.redirectsMap.size === 0) { + // The own map will be for projectCompilerOptions + Debug.assert(moduleResolutionCache.moduleNameToDirectoryMap.redirectsMap.size === 0); + moduleResolutionCache.directoryToModuleNameMap.redirectsMap.set(projPath, moduleResolutionCache.directoryToModuleNameMap.ownMap); + moduleResolutionCache.moduleNameToDirectoryMap.redirectsMap.set(projPath, moduleResolutionCache.moduleNameToDirectoryMap.ownMap); + } + else { + // Set correct own map + Debug.assert(moduleResolutionCache.moduleNameToDirectoryMap.redirectsMap.size > 0); + + const ref: ResolvedProjectReference = { + sourceFile: config.options.configFile!, + commandLine: config + }; + moduleResolutionCache.directoryToModuleNameMap.setOwnMap(moduleResolutionCache.directoryToModuleNameMap.getOrCreateMapOfCacheRedirects(ref)); + moduleResolutionCache.moduleNameToDirectoryMap.setOwnMap(moduleResolutionCache.moduleNameToDirectoryMap.getOrCreateMapOfCacheRedirects(ref)); + } + moduleResolutionCache.directoryToModuleNameMap.setOwnOptions(config.options); + moduleResolutionCache.moduleNameToDirectoryMap.setOwnOptions(config.options); + } + + function checkConfigFileUpToDateStatus(state: SolutionBuilderState, configFile: string, oldestOutputFileTime: Date, oldestOutputFileName: string): Status.OutOfDateWithSelf | undefined { + // Check tsconfig time + const tsconfigTime = state.host.getModifiedTime(configFile) || missingFileModifiedTime; + if (oldestOutputFileTime < tsconfigTime) { + return { + type: UpToDateStatusType.OutOfDateWithSelf, + outOfDateOutputFileName: oldestOutputFileName, + newerInputFileName: configFile + }; + } + } + + function getUpToDateStatusWorker(state: SolutionBuilderState, project: ParsedCommandLine, resolvedPath: ResolvedConfigFilePath): UpToDateStatus { + let newestInputFileName: string = undefined!; + let newestInputFileTime = minimumDate; + const { host } = state; + // Get timestamps of input files + for (const inputFile of project.fileNames) { + if (!host.fileExists(inputFile)) { + return { + type: UpToDateStatusType.Unbuildable, + reason: `${inputFile} does not exist` + }; + } + + const inputTime = host.getModifiedTime(inputFile) || missingFileModifiedTime; + if (inputTime > newestInputFileTime) { + newestInputFileName = inputFile; + newestInputFileTime = inputTime; + } + } + + // Container if no files are specified in the project + if (!project.fileNames.length && !canJsonReportNoInutFiles(project.raw)) { + return { + type: UpToDateStatusType.ContainerOnly + }; + } + + // Collect the expected outputs of this project + const outputs = getAllProjectOutputs(project, !host.useCaseSensitiveFileNames()); + + // Now see if all outputs are newer than the newest input + let oldestOutputFileName = "(none)"; + let oldestOutputFileTime = maximumDate; + let newestOutputFileName = "(none)"; + let newestOutputFileTime = minimumDate; + let missingOutputFileName: string | undefined; + let newestDeclarationFileContentChangedTime = minimumDate; + let isOutOfDateWithInputs = false; + for (const output of outputs) { + // Output is missing; can stop checking + // Don't immediately return because we can still be upstream-blocked, which is a higher-priority status + if (!host.fileExists(output)) { + missingOutputFileName = output; + break; + } + + const outputTime = host.getModifiedTime(output) || missingFileModifiedTime; + if (outputTime < oldestOutputFileTime) { + oldestOutputFileTime = outputTime; + oldestOutputFileName = output; + } + + // If an output is older than the newest input, we can stop checking + // Don't immediately return because we can still be upstream-blocked, which is a higher-priority status + if (outputTime < newestInputFileTime) { + isOutOfDateWithInputs = true; + break; + } + + if (outputTime > newestOutputFileTime) { + newestOutputFileTime = outputTime; + newestOutputFileName = output; + } + + // Keep track of when the most recent time a .d.ts file was changed. + // In addition to file timestamps, we also keep track of when a .d.ts file + // had its file touched but not had its contents changed - this allows us + // to skip a downstream typecheck + if (isDeclarationFile(output)) { + const outputModifiedTime = host.getModifiedTime(output) || missingFileModifiedTime; + newestDeclarationFileContentChangedTime = newer(newestDeclarationFileContentChangedTime, outputModifiedTime); + } + } + + let pseudoUpToDate = false; + let usesPrepend = false; + let upstreamChangedProject: string | undefined; + if (project.projectReferences) { + state.projectStatus.set(resolvedPath, { type: UpToDateStatusType.ComputingUpstream }); + for (const ref of project.projectReferences) { + usesPrepend = usesPrepend || !!(ref.prepend); + const resolvedRef = resolveProjectReferencePath(ref); + const resolvedRefPath = toResolvedConfigFilePath(state, resolvedRef); + const refStatus = getUpToDateStatus(state, parseConfigFile(state, resolvedRef, resolvedRefPath), resolvedRefPath); + + // Its a circular reference ignore the status of this project + if (refStatus.type === UpToDateStatusType.ComputingUpstream) { + continue; + } + + // An upstream project is blocked + if (refStatus.type === UpToDateStatusType.Unbuildable) { + return { + type: UpToDateStatusType.UpstreamBlocked, + upstreamProjectName: ref.path + }; + } + + // If the upstream project is out of date, then so are we (someone shouldn't have asked, though?) + if (refStatus.type !== UpToDateStatusType.UpToDate) { + return { + type: UpToDateStatusType.UpstreamOutOfDate, + upstreamProjectName: ref.path + }; + } + + // Check oldest output file name only if there is no missing output file name + if (!missingOutputFileName) { + // If the upstream project's newest file is older than our oldest output, we + // can't be out of date because of it + if (refStatus.newestInputFileTime && refStatus.newestInputFileTime <= oldestOutputFileTime) { continue; } - if (isDeclarationFile(file)) { - priorNewestUpdateTime = newer(priorNewestUpdateTime, host.getModifiedTime(file) || missingFileModifiedTime); + // If the upstream project has only change .d.ts files, and we've built + // *after* those files, then we're "psuedo up to date" and eligible for a fast rebuild + if (refStatus.newestDeclarationFileContentChangedTime && refStatus.newestDeclarationFileContentChangedTime <= oldestOutputFileTime) { + pseudoUpToDate = true; + upstreamChangedProject = ref.path; + continue; } - host.setModifiedTime(file, now); - listEmittedFile(proj, file); + // We have an output older than an upstream output - we are out of date + Debug.assert(oldestOutputFileName !== undefined, "Should have an oldest output filename here"); + return { + type: UpToDateStatusType.OutOfDateWithUpstream, + outOfDateOutputFileName: oldestOutputFileName, + newerProjectName: ref.path + }; } } - - return priorNewestUpdateTime; } - function getFilesToClean(): string[] { - // Get the same graph for cleaning we'd use for building - const graph = getGlobalDependencyGraph(); - const filesToDelete: string[] = []; - for (const proj of graph.buildQueue) { - const parsed = parseConfigFile(proj); - if (parsed === undefined) { - // File has gone missing; fine to ignore here - reportParseConfigFileDiagnostic(proj); - continue; - } - const outputs = getAllProjectOutputs(parsed, !host.useCaseSensitiveFileNames()); - for (const output of outputs) { - if (host.fileExists(output)) { - filesToDelete.push(output); - } - } - } - return filesToDelete; - } - - function cleanAllProjects() { - const filesToDelete = getFilesToClean(); - if (options.dry) { - reportStatus(Diagnostics.A_non_dry_build_would_delete_the_following_files_Colon_0, filesToDelete.map(f => `\r\n * ${f}`).join("")); - return ExitStatus.Success; - } - - for (const output of filesToDelete) { - host.deleteFile(output); - } - - return ExitStatus.Success; - } - - function resolveProjectName(name: string): ResolvedConfigFileName { - return resolveConfigFileProjectName(resolvePath(host.getCurrentDirectory(), name)); - } - - function resolveProjectNames(configFileNames: ReadonlyArray): ResolvedConfigFileName[] { - return configFileNames.map(resolveProjectName); - } - - function enableCache() { - if (cacheState) { - disableCache(); - } - - const originalReadFileWithCache = readFileWithCache; - const originalGetSourceFile = compilerHost.getSourceFile; - - const { originalReadFile, originalFileExists, originalDirectoryExists, - originalCreateDirectory, originalWriteFile, getSourceFileWithCache, - readFileWithCache: newReadFileWithCache - } = changeCompilerHostLikeToUseCache(host, toPath, (...args) => originalGetSourceFile.call(compilerHost, ...args)); - readFileWithCache = newReadFileWithCache; - compilerHost.getSourceFile = getSourceFileWithCache!; - - const originalResolveModuleNames = compilerHost.resolveModuleNames; - if (!compilerHost.resolveModuleNames) { - const loader = (moduleName: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined) => resolveModuleName(moduleName, containingFile, projectCompilerOptions, compilerHost, moduleResolutionCache, redirectedReference).resolvedModule!; - compilerHost.resolveModuleNames = (moduleNames, containingFile, _reusedNames, redirectedReference) => - loadWithLocalCache(Debug.assertEachDefined(moduleNames), containingFile, redirectedReference, loader); - } - - cacheState = { - originalReadFile, - originalFileExists, - originalDirectoryExists, - originalCreateDirectory, - originalWriteFile, - originalReadFileWithCache, - originalGetSourceFile, - originalResolveModuleNames + if (missingOutputFileName !== undefined) { + return { + type: UpToDateStatusType.OutputMissing, + missingOutputFileName }; } - function disableCache() { - if (!cacheState) return; + if (isOutOfDateWithInputs) { + return { + type: UpToDateStatusType.OutOfDateWithSelf, + outOfDateOutputFileName: oldestOutputFileName, + newerInputFileName: newestInputFileName + }; + } + else { + // Check tsconfig time + const configStatus = checkConfigFileUpToDateStatus(state, project.options.configFilePath!, oldestOutputFileTime, oldestOutputFileName); + if (configStatus) return configStatus; - host.readFile = cacheState.originalReadFile; - host.fileExists = cacheState.originalFileExists; - host.directoryExists = cacheState.originalDirectoryExists; - host.createDirectory = cacheState.originalCreateDirectory; - host.writeFile = cacheState.originalWriteFile; - compilerHost.getSourceFile = cacheState.originalGetSourceFile; - readFileWithCache = cacheState.originalReadFileWithCache; - compilerHost.resolveModuleNames = cacheState.originalResolveModuleNames; - extendedConfigCache.clear(); - if (moduleResolutionCache) { - moduleResolutionCache.directoryToModuleNameMap.clear(); - moduleResolutionCache.moduleNameToDirectoryMap.clear(); - } - cacheState = undefined; + // Check extended config time + const extendedConfigStatus = forEach(project.options.configFile!.extendedSourceFiles || emptyArray, configFile => checkConfigFileUpToDateStatus(state, configFile, oldestOutputFileTime, oldestOutputFileName)); + if (extendedConfigStatus) return extendedConfigStatus; } - function buildAllProjects(): ExitStatus { - if (options.watch) { reportWatchStatus(Diagnostics.Starting_compilation_in_watch_mode); } - enableCache(); + if (!state.buildInfoChecked.has(resolvedPath)) { + state.buildInfoChecked.set(resolvedPath, true); + const buildInfoPath = getOutputPathForBuildInfo(project.options); + if (buildInfoPath) { + const value = state.readFileWithCache(buildInfoPath); + const buildInfo = value && getBuildInfo(value); + if (buildInfo && (buildInfo.bundle || buildInfo.program) && buildInfo.version !== version) { + return { + type: UpToDateStatusType.TsVersionOutputOfDate, + version: buildInfo.version + }; + } + } + } - const graph = getGlobalDependencyGraph(); - reportBuildQueue(graph); - let anyFailed = false; - for (const next of graph.buildQueue) { - const proj = parseConfigFile(next); - if (proj === undefined) { - reportParseConfigFileDiagnostic(next); - anyFailed = true; - break; + if (usesPrepend && pseudoUpToDate) { + return { + type: UpToDateStatusType.OutOfDateWithPrepend, + outOfDateOutputFileName: oldestOutputFileName, + newerProjectName: upstreamChangedProject! + }; + } + + // Up to date + return { + type: pseudoUpToDate ? UpToDateStatusType.UpToDateWithUpstreamTypes : UpToDateStatusType.UpToDate, + newestDeclarationFileContentChangedTime, + newestInputFileTime, + newestOutputFileTime, + newestInputFileName, + newestOutputFileName, + oldestOutputFileName + }; + } + + function getUpToDateStatus(state: SolutionBuilderState, project: ParsedCommandLine | undefined, resolvedPath: ResolvedConfigFilePath): UpToDateStatus { + if (project === undefined) { + return { type: UpToDateStatusType.Unbuildable, reason: "File deleted mid-build" }; + } + + const prior = state.projectStatus.get(resolvedPath); + if (prior !== undefined) { + return prior; + } + + const actual = getUpToDateStatusWorker(state, project, resolvedPath); + state.projectStatus.set(resolvedPath, actual); + return actual; + } + + function updateOutputTimestampsWorker(state: SolutionBuilderState, proj: ParsedCommandLine, priorNewestUpdateTime: Date, verboseMessage: DiagnosticMessage, skipOutputs?: FileMap) { + const { host } = state; + const outputs = getAllProjectOutputs(proj, !host.useCaseSensitiveFileNames()); + if (!skipOutputs || outputs.length !== skipOutputs.size) { + let reportVerbose = !!state.options.verbose; + const now = host.now ? host.now() : new Date(); + for (const file of outputs) { + if (skipOutputs && skipOutputs.has(toPath(state, file))) { + continue; } - // report errors early when using continue or break statements - const errors = proj.errors; - const status = getUpToDateStatus(proj); - verboseReportProjectStatus(next, status); + if (reportVerbose) { + reportVerbose = false; + reportStatus(state, verboseMessage, proj.options.configFilePath!); + } - const projName = proj.options.configFilePath!; - if (status.type === UpToDateStatusType.UpToDate && !options.force) { - reportAndStoreErrors(next, errors); - // Up to date, skip - if (defaultOptions.dry) { - // In a dry build, inform the user of this fact - reportStatus(Diagnostics.Project_0_is_up_to_date, projName); + if (isDeclarationFile(file)) { + priorNewestUpdateTime = newer(priorNewestUpdateTime, host.getModifiedTime(file) || missingFileModifiedTime); + } + + host.setModifiedTime(file, now); + listEmittedFile(state, proj, file); + } + } + + return priorNewestUpdateTime; + } + + function updateOutputTimestamps(state: SolutionBuilderState, proj: ParsedCommandLine, resolvedPath: ResolvedConfigFilePath) { + if (state.options.dry) { + return reportStatus(state, Diagnostics.A_non_dry_build_would_update_timestamps_for_output_of_project_0, proj.options.configFilePath!); + } + const priorNewestUpdateTime = updateOutputTimestampsWorker(state, proj, minimumDate, Diagnostics.Updating_output_timestamps_of_project_0); + state.projectStatus.set(resolvedPath, { + type: UpToDateStatusType.UpToDate, + newestDeclarationFileContentChangedTime: priorNewestUpdateTime, + oldestOutputFileName: getFirstProjectOutput(proj, !state.host.useCaseSensitiveFileNames()) + }); + } + + function queueReferencingProjects( + state: SolutionBuilderState, + project: ResolvedConfigFileName, + projectPath: ResolvedConfigFilePath, + projectIndex: number, + config: ParsedCommandLine, + buildOrder: readonly ResolvedConfigFileName[], + buildResult: BuildResultFlags + ) { + // Queue only if there are no errors + if (buildResult & BuildResultFlags.AnyErrors) return; + // Only composite projects can be referenced by other projects + if (!config.options.composite) return; + // Always use build order to queue projects + for (let index = projectIndex + 1; index < buildOrder.length; index++) { + const nextProject = buildOrder[index]; + const nextProjectPath = toResolvedConfigFilePath(state, nextProject); + if (state.projectPendingBuild.has(nextProjectPath)) continue; + + const nextProjectConfig = parseConfigFile(state, nextProject, nextProjectPath); + if (!nextProjectConfig || !nextProjectConfig.projectReferences) continue; + for (const ref of nextProjectConfig.projectReferences) { + const resolvedRefPath = resolveProjectName(state, ref.path); + if (toResolvedConfigFilePath(state, resolvedRefPath) !== projectPath) continue; + // If the project is referenced with prepend, always build downstream projects, + // If declaration output is changed, build the project + // otherwise mark the project UpToDateWithUpstreamTypes so it updates output time stamps + const status = state.projectStatus.get(nextProjectPath); + if (status) { + switch (status.type) { + case UpToDateStatusType.UpToDate: + if (buildResult & BuildResultFlags.DeclarationOutputUnchanged) { + if (ref.prepend) { + state.projectStatus.set(nextProjectPath, { + type: UpToDateStatusType.OutOfDateWithPrepend, + outOfDateOutputFileName: status.oldestOutputFileName, + newerProjectName: project + }); + } + else { + status.type = UpToDateStatusType.UpToDateWithUpstreamTypes; + } + break; + } + + // falls through + case UpToDateStatusType.UpToDateWithUpstreamTypes: + case UpToDateStatusType.OutOfDateWithPrepend: + if (!(buildResult & BuildResultFlags.DeclarationOutputUnchanged)) { + state.projectStatus.set(nextProjectPath, { + type: UpToDateStatusType.OutOfDateWithUpstream, + outOfDateOutputFileName: status.type === UpToDateStatusType.OutOfDateWithPrepend ? status.outOfDateOutputFileName : status.oldestOutputFileName, + newerProjectName: project + }); + } + break; + + case UpToDateStatusType.UpstreamBlocked: + if (toResolvedConfigFilePath(state, resolveProjectName(state, status.upstreamProjectName)) === projectPath) { + clearProjectStatus(state, nextProjectPath); + } + break; } - continue; } - - if (status.type === UpToDateStatusType.UpToDateWithUpstreamTypes && !options.force) { - reportAndStoreErrors(next, errors); - // Fake build - updateOutputTimestamps(proj); - continue; - } - - if (status.type === UpToDateStatusType.UpstreamBlocked) { - reportAndStoreErrors(next, errors); - if (options.verbose) reportStatus(Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_has_errors, projName, status.upstreamProjectName); - continue; - } - - if (status.type === UpToDateStatusType.ContainerOnly) { - reportAndStoreErrors(next, errors); - // Do nothing - continue; - } - - const buildResult = needsBuild(status, next) ? - buildSingleProject(next) : // Actual build - updateBundle(next); // Fake that files have been built by manipulating prepend and existing output - - anyFailed = anyFailed || !!(buildResult & BuildResultFlags.AnyErrors); + addProjToQueue(state, nextProjectPath, ConfigFileProgramReloadLevel.None); + break; } - reportErrorSummary(); - disableCache(); - return anyFailed ? ExitStatus.DiagnosticsPresent_OutputsSkipped : ExitStatus.Success; - } - - function needsBuild(status: UpToDateStatus, configFile: ResolvedConfigFileName) { - if (status.type !== UpToDateStatusType.OutOfDateWithPrepend || options.force) return true; - const config = parseConfigFile(configFile); - return !config || - config.fileNames.length === 0 || - !!config.errors.length || - !isIncrementalCompilation(config.options); - } - - function reportParseConfigFileDiagnostic(proj: ResolvedConfigFileName) { - reportAndStoreErrors(proj, [configFileCache.getValue(proj) as Diagnostic]); - } - - function reportAndStoreErrors(proj: ResolvedConfigFileName, errors: ReadonlyArray) { - reportErrors(errors); - projectErrorsReported.setValue(proj, true); - diagnostics.setValue(proj, errors); - } - - function reportErrors(errors: ReadonlyArray) { - errors.forEach(err => host.reportDiagnostic(err)); - } - - /** - * Report the build ordering inferred from the current project graph if we're in verbose mode - */ - function reportBuildQueue(graph: DependencyGraph) { - if (options.verbose) { - reportStatus(Diagnostics.Projects_in_this_build_Colon_0, graph.buildQueue.map(s => "\r\n * " + relName(s)).join("")); - } - } - - function relName(path: string): string { - return convertToRelativePath(path, host.getCurrentDirectory(), f => compilerHost.getCanonicalFileName(f)); - } - - /** - * Report the up-to-date status of a project if we're in verbose mode - */ - function verboseReportProjectStatus(configFileName: string, status: UpToDateStatus) { - if (!options.verbose) return; - return formatUpToDateStatus(configFileName, status, relName, reportStatus); } } - export function resolveConfigFileProjectName(project: string): ResolvedConfigFileName { - if (fileExtensionIs(project, Extension.Json)) { - return project as ResolvedConfigFileName; + function build(state: SolutionBuilderState, project?: string, cancellationToken?: CancellationToken, onlyReferences?: boolean): ExitStatus { + const buildOrder = getBuildOrderFor(state, project, onlyReferences); + if (!buildOrder) return ExitStatus.InvalidProject_OutputsSkipped; + + setupInitialBuild(state, cancellationToken); + + let reportQueue = true; + let successfulProjects = 0; + let errorProjects = 0; + while (true) { + const invalidatedProject = getNextInvalidatedProject(state, buildOrder, reportQueue); + if (!invalidatedProject) break; + reportQueue = false; + invalidatedProject.done(cancellationToken); + if (state.diagnostics.has(invalidatedProject.projectPath)) { + errorProjects++; + } + else { + successfulProjects++; + } } - return combinePaths(project, "tsconfig.json") as ResolvedConfigFileName; + disableCache(state); + reportErrorSummary(state, buildOrder); + startWatching(state, buildOrder); + + return errorProjects ? + successfulProjects ? + ExitStatus.DiagnosticsPresent_OutputsGenerated : + ExitStatus.DiagnosticsPresent_OutputsSkipped : + ExitStatus.Success; } - export function formatUpToDateStatus(configFileName: string, status: UpToDateStatus, relName: (fileName: string) => string, formatMessage: (message: DiagnosticMessage, ...args: string[]) => T) { + function clean(state: SolutionBuilderState, project?: string, onlyReferences?: boolean) { + const buildOrder = getBuildOrderFor(state, project, onlyReferences); + if (!buildOrder) return ExitStatus.InvalidProject_OutputsSkipped; + + const { options, host } = state; + const filesToDelete = options.dry ? [] as string[] : undefined; + for (const proj of buildOrder) { + const resolvedPath = toResolvedConfigFilePath(state, proj); + const parsed = parseConfigFile(state, proj, resolvedPath); + if (parsed === undefined) { + // File has gone missing; fine to ignore here + reportParseConfigFileDiagnostic(state, resolvedPath); + continue; + } + const outputs = getAllProjectOutputs(parsed, !host.useCaseSensitiveFileNames()); + for (const output of outputs) { + if (host.fileExists(output)) { + if (filesToDelete) { + filesToDelete.push(output); + } + else { + host.deleteFile(output); + invalidateProject(state, resolvedPath, ConfigFileProgramReloadLevel.None); + } + } + } + } + + if (filesToDelete) { + reportStatus(state, Diagnostics.A_non_dry_build_would_delete_the_following_files_Colon_0, filesToDelete.map(f => `\r\n * ${f}`).join("")); + } + + return ExitStatus.Success; + } + + function invalidateProject(state: SolutionBuilderState, resolved: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { + // If host implements getParsedCommandLine, we cant get list of files from parseConfigFileHost + if (state.host.getParsedCommandLine && reloadLevel === ConfigFileProgramReloadLevel.Partial) { + reloadLevel = ConfigFileProgramReloadLevel.Full; + } + if (reloadLevel === ConfigFileProgramReloadLevel.Full) { + state.configFileCache.delete(resolved); + state.buildOrder = undefined; + } + state.needsSummary = true; + clearProjectStatus(state, resolved); + addProjToQueue(state, resolved, reloadLevel); + enableCache(state); + } + + function invalidateProjectAndScheduleBuilds(state: SolutionBuilderState, resolvedPath: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { + state.reportFileChangeDetected = true; + invalidateProject(state, resolvedPath, reloadLevel); + scheduleBuildInvalidatedProject(state); + } + + function scheduleBuildInvalidatedProject(state: SolutionBuilderState) { + const { hostWithWatch } = state; + if (!hostWithWatch.setTimeout || !hostWithWatch.clearTimeout) { + return; + } + if (state.timerToBuildInvalidatedProject) { + hostWithWatch.clearTimeout(state.timerToBuildInvalidatedProject); + } + state.timerToBuildInvalidatedProject = hostWithWatch.setTimeout(buildNextInvalidatedProject, 250, state); + } + + function buildNextInvalidatedProject(state: SolutionBuilderState) { + state.timerToBuildInvalidatedProject = undefined; + if (state.reportFileChangeDetected) { + state.reportFileChangeDetected = false; + state.projectErrorsReported.clear(); + reportWatchStatus(state, Diagnostics.File_change_detected_Starting_incremental_compilation); + } + const buildOrder = getBuildOrder(state); + const invalidatedProject = getNextInvalidatedProject(state, buildOrder, /*reportQueue*/ false); + if (invalidatedProject) { + invalidatedProject.done(); + if (state.projectPendingBuild.size) { + // Schedule next project for build + if (state.watch && !state.timerToBuildInvalidatedProject) { + scheduleBuildInvalidatedProject(state); + } + return; + } + } + disableCache(state); + reportErrorSummary(state, buildOrder); + } + + function watchConfigFile(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath) { + if (!state.watch || state.allWatchedConfigFiles.has(resolvedPath)) return; + state.allWatchedConfigFiles.set(resolvedPath, state.watchFile( + state.hostWithWatch, + resolved, + () => { + invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.Full); + }, + PollingInterval.High, + WatchType.ConfigFile, + resolved + )); + } + + function isSameFile(state: SolutionBuilderState, file1: string, file2: string) { + return comparePaths(file1, file2, state.currentDirectory, !state.host.useCaseSensitiveFileNames()) === Comparison.EqualTo; + } + + function isOutputFile(state: SolutionBuilderState, fileName: string, configFile: ParsedCommandLine) { + if (configFile.options.noEmit) return false; + + // ts or tsx files are not output + if (!fileExtensionIs(fileName, Extension.Dts) && + (fileExtensionIs(fileName, Extension.Ts) || fileExtensionIs(fileName, Extension.Tsx))) { + return false; + } + + // If options have --outFile or --out, check if its that + const out = configFile.options.outFile || configFile.options.out; + if (out && (isSameFile(state, fileName, out) || isSameFile(state, fileName, removeFileExtension(out) + Extension.Dts))) { + return true; + } + + // If declarationDir is specified, return if its a file in that directory + if (configFile.options.declarationDir && containsPath(configFile.options.declarationDir, fileName, state.currentDirectory, !state.host.useCaseSensitiveFileNames())) { + return true; + } + + // If --outDir, check if file is in that directory + if (configFile.options.outDir && containsPath(configFile.options.outDir, fileName, state.currentDirectory, !state.host.useCaseSensitiveFileNames())) { + return true; + } + + return !forEach(configFile.fileNames, inputFile => isSameFile(state, fileName, inputFile)); + } + + function watchWildCardDirectories(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine) { + if (!state.watch) return; + updateWatchingWildcardDirectories( + getOrCreateValueMapFromConfigFileMap(state.allWatchedWildcardDirectories, resolvedPath), + createMapFromTemplate(parsed.configFileSpecs!.wildcardDirectories), + (dir, flags) => state.watchDirectory( + state.hostWithWatch, + dir, + fileOrDirectory => { + const fileOrDirectoryPath = toPath(state, fileOrDirectory); + if (fileOrDirectoryPath !== toPath(state, dir) && hasExtension(fileOrDirectoryPath) && !isSupportedSourceFileName(fileOrDirectory, parsed.options)) { + state.writeLog(`Project: ${resolved} Detected file add/remove of non supported extension: ${fileOrDirectory}`); + return; + } + + if (isOutputFile(state, fileOrDirectory, parsed)) { + state.writeLog(`${fileOrDirectory} is output file`); + return; + } + + invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.Partial); + }, + flags, + WatchType.WildcardDirectory, + resolved + ) + ); + } + + function watchInputFiles(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine) { + if (!state.watch) return; + mutateMap( + getOrCreateValueMapFromConfigFileMap(state.allWatchedInputFiles, resolvedPath), + arrayToMap(parsed.fileNames, fileName => toPath(state, fileName)), + { + createNewValue: (path, input) => state.watchFilePath( + state.hostWithWatch, + input, + () => invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.None), + PollingInterval.Low, + path as Path, + WatchType.SourceFile, + resolved + ), + onDeleteValue: closeFileWatcher, + } + ); + } + + function startWatching(state: SolutionBuilderState, buildOrder: readonly ResolvedConfigFileName[]) { + if (!state.watchAllProjectsPending) return; + state.watchAllProjectsPending = false; + for (const resolved of buildOrder) { + const resolvedPath = toResolvedConfigFilePath(state, resolved); + // Watch this file + watchConfigFile(state, resolved, resolvedPath); + + const cfg = parseConfigFile(state, resolved, resolvedPath); + if (cfg) { + // Update watchers for wildcard directories + watchWildCardDirectories(state, resolved, resolvedPath, cfg); + + // Watch input files + watchInputFiles(state, resolved, resolvedPath, cfg); + } + } + } + + /** + * A SolutionBuilder has an immutable set of rootNames that are the "entry point" projects, but + * can dynamically add/remove other projects based on changes on the rootNames' references + */ + function createSolutionBuilderWorker(watch: false, host: SolutionBuilderHost, rootNames: ReadonlyArray, defaultOptions: BuildOptions): SolutionBuilder; + function createSolutionBuilderWorker(watch: true, host: SolutionBuilderWithWatchHost, rootNames: ReadonlyArray, defaultOptions: BuildOptions): SolutionBuilder; + function createSolutionBuilderWorker(watch: boolean, hostOrHostWithWatch: SolutionBuilderHost | SolutionBuilderWithWatchHost, rootNames: ReadonlyArray, options: BuildOptions): SolutionBuilder { + const state = createSolutionBuilderState(watch, hostOrHostWithWatch, rootNames, options); + return { + build: (project, cancellationToken) => build(state, project, cancellationToken), + clean: project => clean(state, project), + buildReferences: (project, cancellationToken) => build(state, project, cancellationToken, /*onlyReferences*/ true), + cleanReferences: project => clean(state, project, /*onlyReferences*/ true), + getNextInvalidatedProject: cancellationToken => { + setupInitialBuild(state, cancellationToken); + return getNextInvalidatedProject(state, getBuildOrder(state), /*reportQueue*/ false); + }, + getBuildOrder: () => getBuildOrder(state), + getUpToDateStatusOfProject: project => { + const configFileName = resolveProjectName(state, project); + const configFilePath = toResolvedConfigFilePath(state, configFileName); + return getUpToDateStatus(state, parseConfigFile(state, configFileName, configFilePath), configFilePath); + }, + invalidateProject: (configFilePath, reloadLevel) => invalidateProject(state, configFilePath, reloadLevel || ConfigFileProgramReloadLevel.None), + buildNextInvalidatedProject: () => buildNextInvalidatedProject(state), + }; + } + + function relName(state: SolutionBuilderState, path: string): string { + return convertToRelativePath(path, state.currentDirectory, f => state.getCanonicalFileName(f)); + } + + function reportStatus(state: SolutionBuilderState, message: DiagnosticMessage, ...args: string[]) { + state.host.reportSolutionBuilderStatus(createCompilerDiagnostic(message, ...args)); + } + + function reportWatchStatus(state: SolutionBuilderState, message: DiagnosticMessage, ...args: (string | number | undefined)[]) { + if (state.hostWithWatch.onWatchStatusChange) { + state.hostWithWatch.onWatchStatusChange(createCompilerDiagnostic(message, ...args), state.host.getNewLine(), state.baseCompilerOptions); + } + } + + function reportErrors({ host }: SolutionBuilderState, errors: ReadonlyArray) { + errors.forEach(err => host.reportDiagnostic(err)); + } + + function reportAndStoreErrors(state: SolutionBuilderState, proj: ResolvedConfigFilePath, errors: ReadonlyArray) { + reportErrors(state, errors); + state.projectErrorsReported.set(proj, true); + if (errors.length) { + state.diagnostics.set(proj, errors); + } + } + + function reportParseConfigFileDiagnostic(state: SolutionBuilderState, proj: ResolvedConfigFilePath) { + reportAndStoreErrors(state, proj, [state.configFileCache.get(proj) as Diagnostic]); + } + + function reportErrorSummary(state: SolutionBuilderState, buildOrder: readonly ResolvedConfigFileName[]) { + if (!state.needsSummary || (!state.watch && !state.host.reportErrorSummary)) return; + state.needsSummary = false; + const { diagnostics } = state; + // Report errors from the other projects + buildOrder.forEach(project => { + const projectPath = toResolvedConfigFilePath(state, project); + if (!state.projectErrorsReported.has(projectPath)) { + reportErrors(state, diagnostics.get(projectPath) || emptyArray); + } + }); + let totalErrors = 0; + diagnostics.forEach(singleProjectErrors => totalErrors += getErrorCountForSummary(singleProjectErrors)); + if (state.watch) { + reportWatchStatus(state, getWatchErrorSummaryDiagnosticMessage(totalErrors), totalErrors); + } + else { + state.host.reportErrorSummary!(totalErrors); + } + } + + /** + * Report the build ordering inferred from the current project graph if we're in verbose mode + */ + function reportBuildQueue(state: SolutionBuilderState, buildQueue: readonly ResolvedConfigFileName[]) { + if (state.options.verbose) { + reportStatus(state, Diagnostics.Projects_in_this_build_Colon_0, buildQueue.map(s => "\r\n * " + relName(state, s)).join("")); + } + } + + function reportUpToDateStatus(state: SolutionBuilderState, configFileName: string, status: UpToDateStatus) { switch (status.type) { case UpToDateStatusType.OutOfDateWithSelf: - return formatMessage(Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2, - relName(configFileName), - relName(status.outOfDateOutputFileName), - relName(status.newerInputFileName)); + return reportStatus( + state, + Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2, + relName(state, configFileName), + relName(state, status.outOfDateOutputFileName), + relName(state, status.newerInputFileName) + ); case UpToDateStatusType.OutOfDateWithUpstream: - return formatMessage(Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2, - relName(configFileName), - relName(status.outOfDateOutputFileName), - relName(status.newerProjectName)); + return reportStatus( + state, + Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2, + relName(state, configFileName), + relName(state, status.outOfDateOutputFileName), + relName(state, status.newerProjectName) + ); case UpToDateStatusType.OutputMissing: - return formatMessage(Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, - relName(configFileName), - relName(status.missingOutputFileName)); + return reportStatus( + state, + Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, + relName(state, configFileName), + relName(state, status.missingOutputFileName) + ); case UpToDateStatusType.UpToDate: if (status.newestInputFileTime !== undefined) { - return formatMessage(Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, - relName(configFileName), - relName(status.newestInputFileName || ""), - relName(status.oldestOutputFileName || "")); + return reportStatus( + state, + Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, + relName(state, configFileName), + relName(state, status.newestInputFileName || ""), + relName(state, status.oldestOutputFileName || "") + ); } // Don't report anything for "up to date because it was already built" -- too verbose break; case UpToDateStatusType.OutOfDateWithPrepend: - return formatMessage(Diagnostics.Project_0_is_out_of_date_because_output_of_its_dependency_1_has_changed, - relName(configFileName), - relName(status.newerProjectName)); + return reportStatus( + state, + Diagnostics.Project_0_is_out_of_date_because_output_of_its_dependency_1_has_changed, + relName(state, configFileName), + relName(state, status.newerProjectName) + ); case UpToDateStatusType.UpToDateWithUpstreamTypes: - return formatMessage(Diagnostics.Project_0_is_up_to_date_with_d_ts_files_from_its_dependencies, - relName(configFileName)); + return reportStatus( + state, + Diagnostics.Project_0_is_up_to_date_with_d_ts_files_from_its_dependencies, + relName(state, configFileName) + ); case UpToDateStatusType.UpstreamOutOfDate: - return formatMessage(Diagnostics.Project_0_is_out_of_date_because_its_dependency_1_is_out_of_date, - relName(configFileName), - relName(status.upstreamProjectName)); + return reportStatus( + state, + Diagnostics.Project_0_is_out_of_date_because_its_dependency_1_is_out_of_date, + relName(state, configFileName), + relName(state, status.upstreamProjectName) + ); case UpToDateStatusType.UpstreamBlocked: - return formatMessage(Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_has_errors, - relName(configFileName), - relName(status.upstreamProjectName)); + return reportStatus( + state, + Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_has_errors, + relName(state, configFileName), + relName(state, status.upstreamProjectName) + ); case UpToDateStatusType.Unbuildable: - return formatMessage(Diagnostics.Failed_to_parse_file_0_Colon_1, - relName(configFileName), - status.reason); + return reportStatus( + state, + Diagnostics.Failed_to_parse_file_0_Colon_1, + relName(state, configFileName), + status.reason + ); case UpToDateStatusType.TsVersionOutputOfDate: - return formatMessage(Diagnostics.Project_0_is_out_of_date_because_output_for_it_was_generated_with_version_1_that_differs_with_current_version_2, - relName(configFileName), + return reportStatus( + state, + Diagnostics.Project_0_is_out_of_date_because_output_for_it_was_generated_with_version_1_that_differs_with_current_version_2, + relName(state, configFileName), status.version, - version); + version + ); case UpToDateStatusType.ContainerOnly: - // Don't report status on "solution" projects + // Don't report status on "solution" projects case UpToDateStatusType.ComputingUpstream: // Should never leak from getUptoDateStatusWorker break; @@ -1621,4 +2105,13 @@ namespace ts { assertType(status); } } + + /** + * Report the up-to-date status of a project if we're in verbose mode + */ + function verboseReportProjectStatus(state: SolutionBuilderState, configFileName: string, status: UpToDateStatus) { + if (state.options.verbose) { + reportUpToDateStatus(state, configFileName, status); + } + } } diff --git a/src/compiler/tsconfig.json b/src/compiler/tsconfig.json index fdc0ff2969f..f5e16b0d127 100644 --- a/src/compiler/tsconfig.json +++ b/src/compiler/tsconfig.json @@ -30,6 +30,7 @@ "transformers/utilities.ts", "transformers/destructuring.ts", "transformers/ts.ts", + "transformers/classFields.ts", "transformers/es2017.ts", "transformers/es2018.ts", "transformers/es2019.ts", diff --git a/src/compiler/types.ts b/src/compiler/types.ts index db1a62937e6..31fb4984507 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3068,6 +3068,9 @@ namespace ts { // Diagnostics were produced and outputs were generated in spite of them. DiagnosticsPresent_OutputsGenerated = 2, + + // When build skipped because passed in project is invalid + InvalidProject_OutputsSkipped = 3, } export interface EmitResult { @@ -3154,6 +3157,7 @@ namespace ts { */ getExportSymbolOfSymbol(symbol: Symbol): Symbol; getPropertySymbolOfDestructuringAssignment(location: Identifier): Symbol | undefined; + getTypeOfAssignmentPattern(pattern: AssignmentPattern): Type; getTypeAtLocation(node: Node): Type; getTypeFromTypeNode(node: TypeNode): Type; @@ -3751,6 +3755,8 @@ namespace ts { extendedContainers?: Symbol[]; // Containers (other than the parent) which this symbol is aliased in extendedContainersByFile?: Map; // Containers (other than the parent) which this symbol is aliased in variances?: VarianceFlags[]; // Alias symbol type argument variance cache + deferralConstituents?: Type[]; // Calculated list of constituents for a deferred type + deferralParent?: Type; // Source union/intersection of a deferred type } /* @internal */ @@ -3777,6 +3783,7 @@ namespace ts { ReverseMapped = 1 << 13, // Property of reverse-inferred homomorphic mapped type OptionalParameter = 1 << 14, // Optional parameter RestParameter = 1 << 15, // Rest parameter + DeferredType = 1 << 16, // Calculation of the type of this symbol is deferred due to processing costs, should be fetched with `getTypeOfSymbolWithDeferredType` Synthetic = SyntheticProperty | SyntheticMethod, Discriminant = HasNonUniformType | HasLiteralType, Partial = ReadPartial | WritePartial @@ -4009,6 +4016,8 @@ namespace ts { restrictiveInstantiation?: Type; // Instantiation with type parameters mapped to unconstrained form /* @internal */ immediateBaseConstraint?: Type; // Immediate base constraint cache + /* @internal */ + widened?: Type; // Cached widened form of the type } /* @internal */ @@ -5188,6 +5197,7 @@ namespace ts { ContainsYield = 1 << 17, ContainsHoistedDeclarationOrCompletion = 1 << 18, ContainsDynamicImport = 1 << 19, + ContainsClassFields = 1 << 20, // Please leave this as 1 << 29. // It is the maximum bit we can set before we outgrow the size of a v8 small integer (SMI) on an x86 system. diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index f9bf2a8468d..7e5a49dfaf1 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -88,8 +88,6 @@ namespace ts { return result; } - export type ReportEmitErrorSummary = (errorCount: number) => void; - export function getErrorCountForSummary(diagnostics: ReadonlyArray) { return countWhere(diagnostics, diagnostic => diagnostic.category === DiagnosticCategory.Error); } @@ -113,12 +111,12 @@ namespace ts { getCurrentDirectory(): string; getCompilerOptions(): CompilerOptions; getSourceFiles(): ReadonlyArray; - getSyntacticDiagnostics(): ReadonlyArray; - getOptionsDiagnostics(): ReadonlyArray; - getGlobalDiagnostics(): ReadonlyArray; - getSemanticDiagnostics(): ReadonlyArray; + getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray; + getOptionsDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray; + getGlobalDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray; + getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray; getConfigFileParsingDiagnostics(): ReadonlyArray; - emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback): EmitResult; + emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult; } export function listFiles(program: ProgramToEmitFilesAndReportErrors, writeFileName: (s: string) => void) { @@ -132,25 +130,35 @@ namespace ts { /** * Helper that emit files, report diagnostics and lists emitted and/or source files depending on compiler options */ - export function emitFilesAndReportErrors(program: ProgramToEmitFilesAndReportErrors, reportDiagnostic: DiagnosticReporter, writeFileName?: (s: string) => void, reportSummary?: ReportEmitErrorSummary, writeFile?: WriteFileCallback) { + export function emitFilesAndReportErrors( + program: ProgramToEmitFilesAndReportErrors, + reportDiagnostic: DiagnosticReporter, + writeFileName?: (s: string) => void, + reportSummary?: ReportEmitErrorSummary, + writeFile?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnlyDtsFiles?: boolean, + customTransformers?: CustomTransformers + ) { // First get and report any syntactic errors. const diagnostics = program.getConfigFileParsingDiagnostics().slice(); const configFileParsingDiagnosticsLength = diagnostics.length; - addRange(diagnostics, program.getSyntacticDiagnostics()); + addRange(diagnostics, program.getSyntacticDiagnostics(/*sourceFile*/ undefined, cancellationToken)); // If we didn't have any syntactic errors, then also try getting the global and // semantic errors. if (diagnostics.length === configFileParsingDiagnosticsLength) { - addRange(diagnostics, program.getOptionsDiagnostics()); - addRange(diagnostics, program.getGlobalDiagnostics()); + addRange(diagnostics, program.getOptionsDiagnostics(cancellationToken)); + addRange(diagnostics, program.getGlobalDiagnostics(cancellationToken)); if (diagnostics.length === configFileParsingDiagnosticsLength) { - addRange(diagnostics, program.getSemanticDiagnostics()); + addRange(diagnostics, program.getSemanticDiagnostics(/*sourceFile*/ undefined, cancellationToken)); } } // Emit and report any errors we ran into. - const { emittedFiles, emitSkipped, diagnostics: emitDiagnostics } = program.emit(/*targetSourceFile*/ undefined, writeFile); + const emitResult = program.emit(/*targetSourceFile*/ undefined, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers); + const { emittedFiles, diagnostics: emitDiagnostics } = emitResult; addRange(diagnostics, emitDiagnostics); sortAndDeduplicateDiagnostics(diagnostics).forEach(reportDiagnostic); @@ -167,7 +175,34 @@ namespace ts { reportSummary(getErrorCountForSummary(diagnostics)); } - if (emitSkipped && diagnostics.length > 0) { + return { + emitResult, + diagnostics, + }; + } + + export function emitFilesAndReportErrorsAndGetExitStatus( + program: ProgramToEmitFilesAndReportErrors, + reportDiagnostic: DiagnosticReporter, + writeFileName?: (s: string) => void, + reportSummary?: ReportEmitErrorSummary, + writeFile?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnlyDtsFiles?: boolean, + customTransformers?: CustomTransformers + ) { + const { emitResult, diagnostics } = emitFilesAndReportErrors( + program, + reportDiagnostic, + writeFileName, + reportSummary, + writeFile, + cancellationToken, + emitOnlyDtsFiles, + customTransformers + ); + + if (emitResult.emitSkipped && diagnostics.length > 0) { // If the emitter didn't emit anything, then pass that value along. return ExitStatus.DiagnosticsPresent_OutputsSkipped; } @@ -375,6 +410,33 @@ namespace ts { return host; } + export interface IncrementalCompilationOptions { + rootNames: ReadonlyArray; + options: CompilerOptions; + configFileParsingDiagnostics?: ReadonlyArray; + projectReferences?: ReadonlyArray; + host?: CompilerHost; + reportDiagnostic?: DiagnosticReporter; + reportErrorSummary?: ReportEmitErrorSummary; + afterProgramEmitAndDiagnostics?(program: EmitAndSemanticDiagnosticsBuilderProgram): void; + system?: System; + } + export function performIncrementalCompilation(input: IncrementalCompilationOptions) { + const system = input.system || sys; + const host = input.host || (input.host = createIncrementalCompilerHost(input.options, system)); + const builderProgram = createIncrementalProgram(input); + const exitStatus = emitFilesAndReportErrorsAndGetExitStatus( + builderProgram, + input.reportDiagnostic || createDiagnosticReporter(system), + s => host.trace && host.trace(s), + input.reportErrorSummary || input.options.pretty ? errorCount => system.write(getErrorSummaryText(errorCount, system.newLine)) : undefined + ); + if (input.afterProgramEmitAndDiagnostics) input.afterProgramEmitAndDiagnostics(builderProgram); + return exitStatus; + } +} + +namespace ts { export function readBuilderProgram(compilerOptions: CompilerOptions, readFile: (path: string) => string | undefined) { if (compilerOptions.out || compilerOptions.outFile) return undefined; const buildInfoPath = getOutputPathForBuildInfo(compilerOptions); @@ -395,7 +457,7 @@ namespace ts { return host; } - interface IncrementalProgramOptions { + export interface IncrementalProgramOptions { rootNames: ReadonlyArray; options: CompilerOptions; configFileParsingDiagnostics?: ReadonlyArray; @@ -403,7 +465,8 @@ namespace ts { host?: CompilerHost; createProgram?: CreateProgram; } - function createIncrementalProgram({ + + export function createIncrementalProgram({ rootNames, options, configFileParsingDiagnostics, projectReferences, host, createProgram }: IncrementalProgramOptions): T { host = host || createIncrementalCompilerHost(options); @@ -412,33 +475,6 @@ namespace ts { return createProgram(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences); } - export interface IncrementalCompilationOptions { - rootNames: ReadonlyArray; - options: CompilerOptions; - configFileParsingDiagnostics?: ReadonlyArray; - projectReferences?: ReadonlyArray; - host?: CompilerHost; - reportDiagnostic?: DiagnosticReporter; - reportErrorSummary?: ReportEmitErrorSummary; - afterProgramEmitAndDiagnostics?(program: EmitAndSemanticDiagnosticsBuilderProgram): void; - system?: System; - } - export function performIncrementalCompilation(input: IncrementalCompilationOptions) { - const system = input.system || sys; - const host = input.host || (input.host = createIncrementalCompilerHost(input.options, system)); - const builderProgram = createIncrementalProgram(input); - const exitStatus = emitFilesAndReportErrors( - builderProgram, - input.reportDiagnostic || createDiagnosticReporter(system), - s => host.trace && host.trace(s), - input.reportErrorSummary || input.options.pretty ? errorCount => system.write(getErrorSummaryText(errorCount, system.newLine)) : undefined - ); - if (input.afterProgramEmitAndDiagnostics) input.afterProgramEmitAndDiagnostics(builderProgram); - return exitStatus; - } -} - -namespace ts { export type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void; /** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */ export type CreateProgram = (rootNames: ReadonlyArray | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray, projectReferences?: ReadonlyArray | undefined) => T; @@ -691,6 +727,7 @@ namespace ts { hasChangedAutomaticTypeDirectiveNames = true; scheduleProgramUpdate(); }; + compilerHost.fileIsOpen = returnFalse; compilerHost.maxNumberOfFilesToIterateForInvalidation = host.maxNumberOfFilesToIterateForInvalidation; compilerHost.getCurrentProgram = getCurrentProgram; compilerHost.writeLog = writeLog; diff --git a/src/harness/fakes.ts b/src/harness/fakes.ts index 489a41dd677..31e64e2c931 100644 --- a/src/harness/fakes.ts +++ b/src/harness/fakes.ts @@ -388,10 +388,42 @@ namespace fakes { return ts.compareStringsCaseSensitive(ts.isString(a) ? a : a[0], ts.isString(b) ? b : b[0]); } + export function sanitizeBuildInfoProgram(buildInfo: ts.BuildInfo) { + if (buildInfo.program) { + // reference Map + if (buildInfo.program.referencedMap) { + const referencedMap: ts.MapLike = {}; + for (const path of ts.getOwnKeys(buildInfo.program.referencedMap).sort()) { + referencedMap[path] = buildInfo.program.referencedMap[path].sort(); + } + buildInfo.program.referencedMap = referencedMap; + } + + // exportedModulesMap + if (buildInfo.program.exportedModulesMap) { + const exportedModulesMap: ts.MapLike = {}; + for (const path of ts.getOwnKeys(buildInfo.program.exportedModulesMap).sort()) { + exportedModulesMap[path] = buildInfo.program.exportedModulesMap[path].sort(); + } + buildInfo.program.exportedModulesMap = exportedModulesMap; + } + + // semanticDiagnosticsPerFile + if (buildInfo.program.semanticDiagnosticsPerFile) { + buildInfo.program.semanticDiagnosticsPerFile.sort(compareProgramBuildInfoDiagnostic); + } + } + } + export const version = "FakeTSVersion"; export class SolutionBuilderHost extends CompilerHost implements ts.SolutionBuilderHost { - createProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram; + createProgram: ts.CreateProgram; + + constructor(sys: System | vfs.FileSystem, options?: ts.CompilerOptions, setParentNodes?: boolean, createProgram?: ts.CreateProgram) { + super(sys, options, setParentNodes); + this.createProgram = createProgram || ts.createEmitAndSemanticDiagnosticsBuilderProgram; + } readFile(path: string) { const value = super.readFile(path); @@ -405,30 +437,7 @@ namespace fakes { public writeFile(fileName: string, content: string, writeByteOrderMark: boolean) { if (!ts.isBuildInfoFile(fileName)) return super.writeFile(fileName, content, writeByteOrderMark); const buildInfo = ts.getBuildInfo(content); - if (buildInfo.program) { - // reference Map - if (buildInfo.program.referencedMap) { - const referencedMap: ts.MapLike = {}; - for (const path of ts.getOwnKeys(buildInfo.program.referencedMap).sort()) { - referencedMap[path] = buildInfo.program.referencedMap[path].sort(); - } - buildInfo.program.referencedMap = referencedMap; - } - - // exportedModulesMap - if (buildInfo.program.exportedModulesMap) { - const exportedModulesMap: ts.MapLike = {}; - for (const path of ts.getOwnKeys(buildInfo.program.exportedModulesMap).sort()) { - exportedModulesMap[path] = buildInfo.program.exportedModulesMap[path].sort(); - } - buildInfo.program.exportedModulesMap = exportedModulesMap; - } - - // semanticDiagnosticsPerFile - if (buildInfo.program.semanticDiagnosticsPerFile) { - buildInfo.program.semanticDiagnosticsPerFile.sort(compareProgramBuildInfoDiagnostic); - } - } + sanitizeBuildInfoProgram(buildInfo); buildInfo.version = version; super.writeFile(fileName, ts.getBuildInfoText(buildInfo), writeByteOrderMark); } diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 2061bbd69ba..252d9723209 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -1218,7 +1218,7 @@ Actual: ${stringify(fullActual)}`); } } - public verifySignatureHelpPresence(expectPresent: boolean, triggerReason: ts.SignatureHelpTriggerReason | undefined, markers: ReadonlyArray) { + public verifySignatureHelpPresence(expectPresent: boolean, triggerReason: ts.SignatureHelpTriggerReason | undefined, markers: ReadonlyArray) { if (markers.length) { for (const marker of markers) { this.goToMarker(marker); @@ -3786,15 +3786,15 @@ namespace FourSlashInterface { assert(ranges.length !== 0, "Array of ranges is expected to be non-empty"); } - public noSignatureHelp(...markers: string[]): void { + public noSignatureHelp(...markers: (string | FourSlash.Marker)[]): void { this.state.verifySignatureHelpPresence(/*expectPresent*/ false, /*triggerReason*/ undefined, markers); } - public noSignatureHelpForTriggerReason(reason: ts.SignatureHelpTriggerReason, ...markers: string[]): void { + public noSignatureHelpForTriggerReason(reason: ts.SignatureHelpTriggerReason, ...markers: (string | FourSlash.Marker)[]): void { this.state.verifySignatureHelpPresence(/*expectPresent*/ false, reason, markers); } - public signatureHelpPresentForTriggerReason(reason: ts.SignatureHelpTriggerReason, ...markers: string[]): void { + public signatureHelpPresentForTriggerReason(reason: ts.SignatureHelpTriggerReason, ...markers: (string | FourSlash.Marker)[]): void { this.state.verifySignatureHelpPresence(/*expectPresent*/ true, reason, markers); } @@ -5142,7 +5142,7 @@ namespace FourSlashInterface { } export interface VerifySignatureHelpOptions { - readonly marker?: ArrayOrSingle; + readonly marker?: ArrayOrSingle; /** @default 1 */ readonly overloadsCount?: number; /** @default undefined */ diff --git a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl index 0078e878dbc..6720bf0c191 100644 --- a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2881,7 +2881,7 @@ - + @@ -3667,7 +3667,7 @@ - + @@ -3685,7 +3685,7 @@ - + @@ -3694,7 +3694,7 @@ - + @@ -4369,7 +4369,7 @@ - + @@ -4399,7 +4399,7 @@ - + @@ -5242,7 +5242,7 @@ - + @@ -5251,7 +5251,7 @@ - + @@ -5935,7 +5935,7 @@ - + @@ -5971,7 +5971,7 @@ - + @@ -5980,7 +5980,7 @@ - + @@ -5998,7 +5998,7 @@ - + @@ -6007,7 +6007,7 @@ - + @@ -6016,7 +6016,7 @@ - + @@ -6025,7 +6025,7 @@ - + @@ -6043,7 +6043,7 @@ - + @@ -6052,7 +6052,7 @@ - + @@ -6061,7 +6061,7 @@ - + @@ -6070,7 +6070,7 @@ - + @@ -6079,7 +6079,7 @@ - + @@ -6088,7 +6088,7 @@ - + @@ -6106,7 +6106,7 @@ - + @@ -6115,7 +6115,7 @@ - + @@ -6133,7 +6133,7 @@ - + @@ -6142,7 +6142,7 @@ - + @@ -6169,7 +6169,7 @@ - + @@ -6178,7 +6178,7 @@ - + @@ -6187,7 +6187,7 @@ - + @@ -6196,7 +6196,7 @@ - + @@ -6577,7 +6577,7 @@ - + @@ -6586,7 +6586,7 @@ - + @@ -6595,7 +6595,7 @@ - + @@ -6676,7 +6676,7 @@ - + @@ -6685,7 +6685,7 @@ - + @@ -6703,7 +6703,7 @@ - + @@ -6712,7 +6712,7 @@ - + @@ -6730,7 +6730,7 @@ - + @@ -6739,7 +6739,7 @@ - + @@ -6757,7 +6757,7 @@ - + @@ -6766,7 +6766,7 @@ - + @@ -7090,7 +7090,7 @@ - + @@ -7099,7 +7099,7 @@ - + @@ -7108,7 +7108,7 @@ - + @@ -7117,7 +7117,7 @@ - + @@ -7147,7 +7147,7 @@ - + @@ -7156,7 +7156,7 @@ - + @@ -7165,7 +7165,7 @@ - + @@ -7174,7 +7174,7 @@ - + @@ -7183,7 +7183,7 @@ - + @@ -7192,7 +7192,7 @@ - + @@ -7210,7 +7210,7 @@ - + @@ -7219,7 +7219,7 @@ - + @@ -7237,7 +7237,7 @@ - + @@ -7246,7 +7246,7 @@ - + @@ -7264,7 +7264,7 @@ - + @@ -7273,7 +7273,7 @@ - + @@ -7291,7 +7291,7 @@ - + @@ -7300,7 +7300,7 @@ - + @@ -8692,7 +8692,7 @@ - + @@ -8701,7 +8701,7 @@ - + @@ -8710,7 +8710,7 @@ - + @@ -8719,7 +8719,7 @@ - + @@ -8728,7 +8728,7 @@ - + @@ -8737,7 +8737,7 @@ - + @@ -8746,7 +8746,7 @@ - + @@ -8755,7 +8755,7 @@ - + @@ -8764,7 +8764,7 @@ - + @@ -8839,7 +8839,7 @@ - + @@ -9676,7 +9676,7 @@ - + @@ -9685,7 +9685,7 @@ - + diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 6bfce902a04..b868286ea51 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1003,6 +1003,12 @@ namespace ts.server { fileOrDirectory => { const fileOrDirectoryPath = this.toPath(fileOrDirectory); project.getCachedDirectoryStructureHost().addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath); + + // don't trigger callback on open, existing files + if (project.fileIsOpen(fileOrDirectoryPath)) { + return; + } + if (isPathIgnored(fileOrDirectoryPath)) return; const configFilename = project.getConfigFilePath(); diff --git a/src/server/project.ts b/src/server/project.ts index c204facad5c..e10a0988f71 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -198,13 +198,13 @@ namespace ts.server { return hasOneOrMoreJsAndNoTsFiles(this); } - public static resolveModule(moduleName: string, initialDir: string, host: ServerHost, log: (message: string) => void): {} | undefined { + public static resolveModule(moduleName: string, initialDir: string, host: ServerHost, log: (message: string) => void, logErrors?: (message: string) => void): {} | undefined { const resolvedPath = normalizeSlashes(host.resolvePath(combinePaths(initialDir, "node_modules"))); log(`Loading ${moduleName} from ${initialDir} (resolved to ${resolvedPath})`); const result = host.require!(resolvedPath, moduleName); // TODO: GH#18217 if (result.error) { const err = result.error.stack || result.error.message || JSON.stringify(result.error); - log(`Failed to load module '${moduleName}': ${err}`); + (logErrors || log)(`Failed to load module '${moduleName}' from ${resolvedPath}: ${err}`); return undefined; } return result.module; @@ -457,6 +457,11 @@ namespace ts.server { return this.getTypeAcquisition().enable ? this.projectService.typingsInstaller.globalTypingsCacheLocation : undefined; } + /*@internal*/ + fileIsOpen(filePath: Path) { + return this.projectService.openFiles.has(filePath); + } + /*@internal*/ writeLog(s: string) { this.projectService.logger.info(s); @@ -1142,12 +1147,11 @@ namespace ts.server { protected enablePlugin(pluginConfigEntry: PluginImport, searchPaths: string[], pluginConfigOverrides: Map | undefined) { this.projectService.logger.info(`Enabling plugin ${pluginConfigEntry.name} from candidate paths: ${searchPaths.join(",")}`); - const log = (message: string) => { - this.projectService.logger.info(message); - }; - + const log = (message: string) => this.projectService.logger.info(message); + let errorLogs: string[] | undefined; + const logError = (message: string) => { (errorLogs || (errorLogs = [])).push(message); }; const resolvedModule = firstDefined(searchPaths, searchPath => - Project.resolveModule(pluginConfigEntry.name, searchPath, this.projectService.host, log)); + Project.resolveModule(pluginConfigEntry.name, searchPath, this.projectService.host, log, logError)); if (resolvedModule) { const configurationOverride = pluginConfigOverrides && pluginConfigOverrides.get(pluginConfigEntry.name); if (configurationOverride) { @@ -1160,6 +1164,7 @@ namespace ts.server { this.enableProxy(resolvedModule, pluginConfigEntry); } else { + forEach(errorLogs, log); this.projectService.logger.info(`Couldn't find ${pluginConfigEntry.name}`); } } diff --git a/src/services/completions.ts b/src/services/completions.ts index 1adfc1e480f..9cad080c461 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -49,7 +49,9 @@ namespace ts.Completions { const compilerOptions = program.getCompilerOptions(); const contextToken = findPrecedingToken(position, sourceFile); - if (triggerCharacter && !isValidTrigger(sourceFile, triggerCharacter, contextToken, position)) return undefined; + if (triggerCharacter && !isInString(sourceFile, position, contextToken) && !isValidTrigger(sourceFile, triggerCharacter, contextToken, position)) { + return undefined; + } const stringCompletions = StringCompletions.getStringLiteralCompletions(sourceFile, position, contextToken, typeChecker, compilerOptions, host, log, preferences); if (stringCompletions) { diff --git a/src/services/organizeImports.ts b/src/services/organizeImports.ts index 5bfa0c74ab1..81c9108749f 100644 --- a/src/services/organizeImports.ts +++ b/src/services/organizeImports.ts @@ -89,7 +89,7 @@ namespace ts.OrganizeImports { const usedImports: ImportDeclaration[] = []; for (const importDecl of oldImports) { - const {importClause} = importDecl; + const { importClause, moduleSpecifier } = importDecl; if (!importClause) { // Imports without import clauses are assumed to be included for their side effects and are not removed. @@ -125,6 +125,23 @@ namespace ts.OrganizeImports { if (name || namedBindings) { usedImports.push(updateImportDeclarationAndClause(importDecl, name, namedBindings)); } + // If a module is imported to be augmented, it’s used + else if (hasModuleDeclarationMatchingSpecifier(sourceFile, moduleSpecifier)) { + // If we’re in a declaration file, it’s safe to remove the import clause from it + if (sourceFile.isDeclarationFile) { + usedImports.push(createImportDeclaration( + importDecl.decorators, + importDecl.modifiers, + /*importClause*/ undefined, + moduleSpecifier)); + } + // If we’re not in a declaration file, we can’t remove the import clause even though + // the imported symbols are unused, because removing them makes it look like the import + // declaration has side effects, which will cause it to be preserved in the JS emit. + else { + usedImports.push(importDecl); + } + } } return usedImports; @@ -135,6 +152,13 @@ namespace ts.OrganizeImports { } } + function hasModuleDeclarationMatchingSpecifier(sourceFile: SourceFile, moduleSpecifier: Expression) { + const moduleSpecifierText = isStringLiteral(moduleSpecifier) && moduleSpecifier.text; + return isString(moduleSpecifierText) && some(sourceFile.moduleAugmentations, moduleName => + isStringLiteral(moduleName) + && moduleName.text === moduleSpecifierText); + } + function getExternalModuleName(specifier: Expression) { return specifier !== undefined && isStringLiteralLike(specifier) ? specifier.text diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index 25f958dfc6a..998e45bd461 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -133,11 +133,21 @@ namespace ts.SignatureHelp { } function containsPrecedingToken(startingToken: Node, sourceFile: SourceFile, container: Node) { - const precedingToken = Debug.assertDefined( - findPrecedingToken(startingToken.getFullStart(), sourceFile, startingToken.parent, /*excludeJsdoc*/ true) - ); - - return rangeContainsRange(container, precedingToken); + const pos = startingToken.getFullStart(); + // There’s a possibility that `startingToken.parent` contains only `startingToken` and + // missing nodes, none of which are valid to be returned by `findPrecedingToken`. In that + // case, the preceding token we want is actually higher up the tree—almost definitely the + // next parent, but theoretically the situation with missing nodes might be happening on + // multiple nested levels. + let currentParent: Node | undefined = startingToken.parent; + while (currentParent) { + const precedingToken = findPrecedingToken(pos, sourceFile, currentParent, /*excludeJsdoc*/ true); + if (precedingToken) { + return rangeContainsRange(container, precedingToken); + } + currentParent = currentParent.parent; + } + return Debug.fail("Could not find preceding token"); } export interface ArgumentInfoForCompletions { diff --git a/src/testRunner/unittests/config/projectReferences.ts b/src/testRunner/unittests/config/projectReferences.ts index 3acffd7a8c6..26ed746d279 100644 --- a/src/testRunner/unittests/config/projectReferences.ts +++ b/src/testRunner/unittests/config/projectReferences.ts @@ -325,7 +325,7 @@ namespace ts { }; testProjectReferences(spec, "/alpha/tsconfig.json", (program, host) => { program.emit(); - assert.deepEqual(host.outputs.map(e => e.file).sort(), ["/alpha/bin/src/a.d.ts", "/alpha/bin/src/a.js"]); + assert.deepEqual(host.outputs.map(e => e.file).sort(), ["/alpha/bin/src/a.d.ts", "/alpha/bin/src/a.js", "/alpha/bin/tsconfig.tsbuildinfo"]); }); }); }); diff --git a/src/testRunner/unittests/services/organizeImports.ts b/src/testRunner/unittests/services/organizeImports.ts index 8116b1e268a..c119aadb34e 100644 --- a/src/testRunner/unittests/services/organizeImports.ts +++ b/src/testRunner/unittests/services/organizeImports.ts @@ -1,5 +1,5 @@ namespace ts { - describe("unittests:: services:: Organize imports", () => { + describe("unittests:: services:: organizeImports", () => { describe("Sort imports", () => { it("Sort - non-relative vs non-relative", () => { assertSortsBefore( @@ -343,6 +343,36 @@ import { } from "lib"; }, libFile); + testOrganizeImports("Unused_false_positive_module_augmentation", + { + path: "/test.d.ts", + content: ` +import foo from 'foo'; +import { Caseless } from 'caseless'; + +declare module 'foo' {} +declare module 'caseless' { + interface Caseless { + test(name: KeyType): boolean; + } +}` + }); + + testOrganizeImports("Unused_preserve_imports_for_module_augmentation_in_non_declaration_file", + { + path: "/test.ts", + content: ` +import foo from 'foo'; +import { Caseless } from 'caseless'; + +declare module 'foo' {} +declare module 'caseless' { + interface Caseless { + test(name: KeyType): boolean; + } +}` + }); + testOrganizeImports("Unused_false_positive_shorthand_assignment", { path: "/test.ts", diff --git a/src/testRunner/unittests/tsbuild/emptyFiles.ts b/src/testRunner/unittests/tsbuild/emptyFiles.ts index 17c6644ccc6..38b8b4b5379 100644 --- a/src/testRunner/unittests/tsbuild/emptyFiles.ts +++ b/src/testRunner/unittests/tsbuild/emptyFiles.ts @@ -14,13 +14,11 @@ namespace ts { const builder = createSolutionBuilder(host, ["/src/no-references"], { dry: false, force: false, verbose: false }); host.clearDiagnostics(); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages([Diagnostics.The_files_list_in_config_file_0_is_empty, "/src/no-references/tsconfig.json"]); // Check for outputs to not be written. - for (const output of allExpectedOutputs) { - assert(!fs.existsSync(output), `Expect file ${output} to not exist`); - } + verifyOutputsAbsent(fs, allExpectedOutputs); }); it("does not have empty files diagnostic when files is empty and references are provided", () => { @@ -29,13 +27,11 @@ namespace ts { const builder = createSolutionBuilder(host, ["/src/with-references"], { dry: false, force: false, verbose: false }); host.clearDiagnostics(); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages(/*empty*/); // Check for outputs to be written. - for (const output of allExpectedOutputs) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } + verifyOutputsPresent(fs, allExpectedOutputs); }); }); } diff --git a/src/testRunner/unittests/tsbuild/graphOrdering.ts b/src/testRunner/unittests/tsbuild/graphOrdering.ts index bc1af3f71da..a8f4c3a57a9 100644 --- a/src/testRunner/unittests/tsbuild/graphOrdering.ts +++ b/src/testRunner/unittests/tsbuild/graphOrdering.ts @@ -22,34 +22,32 @@ namespace ts { }); it("orders the graph correctly - specify two roots", () => { - checkGraphOrdering(["A", "G"], ["A", "B", "C", "D", "E", "G"]); + checkGraphOrdering(["A", "G"], ["D", "E", "C", "B", "A", "G"]); }); it("orders the graph correctly - multiple parts of the same graph in various orders", () => { - checkGraphOrdering(["A"], ["A", "B", "C", "D", "E"]); - checkGraphOrdering(["A", "C", "D"], ["A", "B", "C", "D", "E"]); - checkGraphOrdering(["D", "C", "A"], ["A", "B", "C", "D", "E"]); + checkGraphOrdering(["A"], ["D", "E", "C", "B", "A"]); + checkGraphOrdering(["A", "C", "D"], ["D", "E", "C", "B", "A"]); + checkGraphOrdering(["D", "C", "A"], ["D", "E", "C", "B", "A"]); }); it("orders the graph correctly - other orderings", () => { - checkGraphOrdering(["F"], ["F", "E"]); + checkGraphOrdering(["F"], ["E", "F"]); checkGraphOrdering(["E"], ["E"]); - checkGraphOrdering(["F", "C", "A"], ["A", "B", "C", "D", "E", "F"]); + checkGraphOrdering(["F", "C", "A"], ["E", "F", "D", "C", "B", "A"]); }); function checkGraphOrdering(rootNames: string[], expectedBuildSet: string[]) { - const builder = createSolutionBuilder(host!, rootNames, { dry: true, force: false, verbose: false }); + const builder = createSolutionBuilder(host!, rootNames.map(getProjectFileName), { dry: true, force: false, verbose: false }); + const buildQueue = builder.getBuildOrder(); - const projFileNames = rootNames.map(getProjectFileName); - const graph = builder.getBuildGraph(projFileNames); - - assert.sameMembers(graph.buildQueue, expectedBuildSet.map(getProjectFileName)); + assert.deepEqual(buildQueue, expectedBuildSet.map(getProjectFileName)); for (const dep of deps) { const child = getProjectFileName(dep[0]); - if (graph.buildQueue.indexOf(child) < 0) continue; + if (buildQueue.indexOf(child) < 0) continue; const parent = getProjectFileName(dep[1]); - assert.isAbove(graph.buildQueue.indexOf(child), graph.buildQueue.indexOf(parent), `Expecting child ${child} to be built after parent ${parent}`); + assert.isAbove(buildQueue.indexOf(child), buildQueue.indexOf(parent), `Expecting child ${child} to be built after parent ${parent}`); } } diff --git a/src/testRunner/unittests/tsbuild/helpers.ts b/src/testRunner/unittests/tsbuild/helpers.ts index 579573a876e..7aeaba36199 100644 --- a/src/testRunner/unittests/tsbuild/helpers.ts +++ b/src/testRunner/unittests/tsbuild/helpers.ts @@ -82,6 +82,18 @@ declare const console: { log(msg: any): void; };`; return fs; } + export function verifyOutputsPresent(fs: vfs.FileSystem, outputs: readonly string[]) { + for (const output of outputs) { + assert(fs.existsSync(output), `Expect file ${output} to exist`); + } + } + + export function verifyOutputsAbsent(fs: vfs.FileSystem, outputs: readonly string[]) { + for (const output of outputs) { + assert.isFalse(fs.existsSync(output), `Expect file ${output} to not exist`); + } + } + function generateSourceMapBaselineFiles(fs: vfs.FileSystem, mapFileNames: ReadonlyArray) { for (const mapFile of mapFileNames) { if (!fs.existsSync(mapFile)) continue; @@ -172,7 +184,7 @@ declare const console: { log(msg: any): void; };`; } return originalReadFile.call(host, path); }; - builder.buildAllProjects(); + builder.build(); generateSourceMapBaselineFiles(fs, expectedMapFileNames); generateBuildInfoSectionBaselineFiles(fs, expectedBuildInfoFilesForSectionBaselines || emptyArray); fs.makeReadonly(); diff --git a/src/testRunner/unittests/tsbuild/missingExtendedFile.ts b/src/testRunner/unittests/tsbuild/missingExtendedFile.ts index 00e8bfec1e3..881f3fbc030 100644 --- a/src/testRunner/unittests/tsbuild/missingExtendedFile.ts +++ b/src/testRunner/unittests/tsbuild/missingExtendedFile.ts @@ -5,7 +5,7 @@ namespace ts { const fs = projFs.shadow(); const host = new fakes.SolutionBuilderHost(fs); const builder = createSolutionBuilder(host, ["/src/tsconfig.json"], {}); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( [Diagnostics.The_specified_path_does_not_exist_Colon_0, "/src/foobar.json"], [Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, "/src/tsconfig.first.json", "[\"**/*\"]", "[]"], diff --git a/src/testRunner/unittests/tsbuild/outFile.ts b/src/testRunner/unittests/tsbuild/outFile.ts index 48beeef4f61..f562d4dc26b 100644 --- a/src/testRunner/unittests/tsbuild/outFile.ts +++ b/src/testRunner/unittests/tsbuild/outFile.ts @@ -363,21 +363,17 @@ namespace ts { ]; const host = new fakes.SolutionBuilderHost(fs); const builder = createSolutionBuilder(host); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages(...initialExpectedDiagnostics); // Verify they exist - for (const output of expectedOutputs) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } + verifyOutputsPresent(fs, expectedOutputs); host.clearDiagnostics(); - builder.cleanAllProjects(); + builder.clean(); host.assertDiagnosticMessages(/*none*/); // Verify they are gone - for (const output of expectedOutputs) { - assert(!fs.existsSync(output), `Expect file ${output} to not exist`); - } + verifyOutputsAbsent(fs, expectedOutputs); // Subsequent clean shouldn't throw / etc - builder.cleanAllProjects(); + builder.clean(); }); it("verify buildInfo absence results in new build", () => { @@ -388,18 +384,16 @@ namespace ts { ...outputFiles[project.third] ]; const host = new fakes.SolutionBuilderHost(fs); - const builder = createSolutionBuilder(host); - builder.buildAllProjects(); + let builder = createSolutionBuilder(host); + builder.build(); host.assertDiagnosticMessages(...initialExpectedDiagnostics); // Verify they exist - for (const output of expectedOutputs) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } + verifyOutputsPresent(fs, expectedOutputs); // Delete bundle info host.clearDiagnostics(); host.deleteFile(outputFiles[project.first][ext.buildinfo]); - builder.resetBuildContext(); - builder.buildAllProjects(); + builder = createSolutionBuilder(host); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild(relSources[project.first][source.config], relSources[project.second][source.config], relSources[project.third][source.config]), [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, relSources[project.first][source.config], relOutputFiles[project.first][ext.buildinfo]], @@ -416,25 +410,23 @@ namespace ts { const host = new fakes.SolutionBuilderHost(fs); replaceText(fs, sources[project.third][source.config], `"composite": true,`, ""); const builder = createSolutionBuilder(host); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages(...initialExpectedDiagnostics); // Verify they exist - without tsbuildinfo for third project - for (const output of expectedOutputFiles.slice(0, expectedOutputFiles.length - 2)) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } - assert.isFalse(fs.existsSync(outputFiles[project.third][ext.buildinfo]), `Expect file ${outputFiles[project.third][ext.buildinfo]} to not exist`); + verifyOutputsPresent(fs, expectedOutputFiles.slice(0, expectedOutputFiles.length - 2)); + verifyOutputsAbsent(fs, [outputFiles[project.third][ext.buildinfo]]); }); it("rebuilds completely when version in tsbuildinfo doesnt match ts version", () => { const fs = outFileFs.shadow(); const host = new fakes.SolutionBuilderHost(fs); - const builder = createSolutionBuilder(host); - builder.buildAllProjects(); + let builder = createSolutionBuilder(host); + builder.build(); host.assertDiagnosticMessages(...initialExpectedDiagnostics); host.clearDiagnostics(); - builder.resetBuildContext(); + builder = createSolutionBuilder(host); changeCompilerVersion(host); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild(relSources[project.first][source.config], relSources[project.second][source.config], relSources[project.third][source.config]), [Diagnostics.Project_0_is_out_of_date_because_output_for_it_was_generated_with_version_1_that_differs_with_current_version_2, relSources[project.first][source.config], fakes.version, version], @@ -453,16 +445,16 @@ namespace ts { // Build with command line incremental const host = new fakes.SolutionBuilderHost(fs); - const builder = createSolutionBuilder(host, { incremental: true }); - builder.buildAllProjects(); + let builder = createSolutionBuilder(host, { incremental: true }); + builder.build(); host.assertDiagnosticMessages(...initialExpectedDiagnostics); host.clearDiagnostics(); tick(); // Make non incremental build with change in file that doesnt affect dts appendText(fs, relSources[project.first][source.ts][part.one], "console.log(s);"); - builder.resetBuildContext({ verbose: true }); - builder.buildAllProjects(); + builder = createSolutionBuilder(host, { verbose: true }); + builder.build(); host.assertDiagnosticMessages(getExpectedDiagnosticForProjectsInBuild(relSources[project.first][source.config], relSources[project.second][source.config], relSources[project.third][source.config]), [Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2, relSources[project.first][source.config], relOutputFiles[project.first][ext.js], relSources[project.first][source.ts][part.one]], [Diagnostics.Building_project_0, sources[project.first][source.config]], @@ -475,8 +467,8 @@ namespace ts { // Make incremental build with change in file that doesnt affect dts appendText(fs, relSources[project.first][source.ts][part.one], "console.log(s);"); - builder.resetBuildContext({ verbose: true, incremental: true }); - builder.buildAllProjects(); + builder = createSolutionBuilder(host, { verbose: true, incremental: true }); + builder.build(); // Builds completely because tsbuildinfo is old. host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild(relSources[project.first][source.config], relSources[project.second][source.config], relSources[project.third][source.config]), @@ -489,6 +481,33 @@ namespace ts { host.clearDiagnostics(); }); + it("builds till project specified", () => { + const fs = outFileFs.shadow(); + const host = new fakes.SolutionBuilderHost(fs); + const builder = createSolutionBuilder(host, { verbose: false }); + const result = builder.build(sources[project.second][source.config]); + host.assertDiagnosticMessages(/*empty*/); + // First and Third is not built + verifyOutputsAbsent(fs, [...outputFiles[project.first], ...outputFiles[project.third]]); + // second is built + verifyOutputsPresent(fs, outputFiles[project.second]); + assert.equal(result, ExitStatus.Success); + }); + + it("cleans till project specified", () => { + const fs = outFileFs.shadow(); + const host = new fakes.SolutionBuilderHost(fs); + const builder = createSolutionBuilder(host, { verbose: false }); + builder.build(); + const result = builder.clean(sources[project.second][source.config]); + host.assertDiagnosticMessages(/*empty*/); + // First and Third output for present + verifyOutputsPresent(fs, [...outputFiles[project.first], ...outputFiles[project.third]]); + // second is cleaned + verifyOutputsAbsent(fs, outputFiles[project.second]); + assert.equal(result, ExitStatus.Success); + }); + describe("Prepend output with .tsbuildinfo", () => { // Prologues describe("Prologues", () => { @@ -904,7 +923,7 @@ ${internal} enum internalEnum { a, b, c }`); const host = new fakes.SolutionBuilderHost(fs); const builder = createSolutionBuilder(host); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild(relSources[project.first][source.config], relSources[project.second][source.config], relSources[project.third][source.config]), [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, relSources[project.first][source.config], "src/first/first_PART1.js"], @@ -923,9 +942,7 @@ ${internal} enum internalEnum { a, b, c }`); removeFileExtension(f) + Extension.Dts + ".map", ]) ]); - for (const output of expectedOutputFiles) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } + verifyOutputsPresent(fs, expectedOutputFiles); }); }); } diff --git a/src/testRunner/unittests/tsbuild/referencesWithRootDirInParent.ts b/src/testRunner/unittests/tsbuild/referencesWithRootDirInParent.ts index 630cd8575ec..186a43b3c3e 100644 --- a/src/testRunner/unittests/tsbuild/referencesWithRootDirInParent.ts +++ b/src/testRunner/unittests/tsbuild/referencesWithRootDirInParent.ts @@ -19,11 +19,9 @@ namespace ts { const fs = projFs.shadow(); const host = new fakes.SolutionBuilderHost(fs); const builder = createSolutionBuilder(host, ["/src/src/main", "/src/src/other"], {}); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages(/*empty*/); - for (const output of allExpectedOutputs) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } + verifyOutputsPresent(fs, allExpectedOutputs); }); it("verify that it reports error for same .tsbuildinfo file because no rootDir in the base", () => { @@ -39,7 +37,7 @@ namespace ts { replaceText(fs, "/src/tsconfig.base.json", `"rootDir": "./src/",`, ""); const host = new fakes.SolutionBuilderHost(fs); const builder = createSolutionBuilder(host, ["/src/src/main"], { verbose: true }); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild("src/src/other/tsconfig.json", "src/src/main/tsconfig.json"), [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/src/other/tsconfig.json", "src/dist/other.js"], @@ -48,12 +46,8 @@ namespace ts { [Diagnostics.Building_project_0, "/src/src/main/tsconfig.json"], [Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, "/src/dist/tsconfig.tsbuildinfo", "/src/src/other"] ); - for (const output of allExpectedOutputs) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } - for (const output of missingOutputs) { - assert.isFalse(fs.existsSync(output), `Expect file ${output} to not exist`); - } + verifyOutputsPresent(fs, allExpectedOutputs); + verifyOutputsAbsent(fs, missingOutputs); }); it("verify that it reports error for same .tsbuildinfo file", () => { @@ -75,7 +69,7 @@ namespace ts { })); const host = new fakes.SolutionBuilderHost(fs); const builder = createSolutionBuilder(host, ["/src/src/main"], { verbose: true }); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild("src/src/other/tsconfig.json", "src/src/main/tsconfig.json"), [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/src/other/tsconfig.json", "src/dist/other.js"], @@ -84,12 +78,8 @@ namespace ts { [Diagnostics.Building_project_0, "/src/src/main/tsconfig.json"], [Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, "/src/dist/tsconfig.tsbuildinfo", "/src/src/other"] ); - for (const output of allExpectedOutputs) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } - for (const output of missingOutputs) { - assert.isFalse(fs.existsSync(output), `Expect file ${output} to not exist`); - } + verifyOutputsPresent(fs, allExpectedOutputs); + verifyOutputsAbsent(fs, missingOutputs); }); it("verify that it reports no error when .tsbuildinfo differ", () => { @@ -112,7 +102,7 @@ namespace ts { })); const host = new fakes.SolutionBuilderHost(fs); const builder = createSolutionBuilder(host, ["/src/src/main/tsconfig.main.json"], { verbose: true }); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild("src/src/other/tsconfig.other.json", "src/src/main/tsconfig.main.json"), [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/src/other/tsconfig.other.json", "src/dist/other.js"], @@ -120,9 +110,7 @@ namespace ts { [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/src/main/tsconfig.main.json", "src/dist/a.js"], [Diagnostics.Building_project_0, "/src/src/main/tsconfig.main.json"] ); - for (const output of allExpectedOutputs) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } + verifyOutputsPresent(fs, allExpectedOutputs); }); }); } diff --git a/src/testRunner/unittests/tsbuild/resolveJsonModule.ts b/src/testRunner/unittests/tsbuild/resolveJsonModule.ts index 3fc50d72ea5..66bb0dc6e95 100644 --- a/src/testRunner/unittests/tsbuild/resolveJsonModule.ts +++ b/src/testRunner/unittests/tsbuild/resolveJsonModule.ts @@ -19,13 +19,11 @@ namespace ts { function verifyProjectWithResolveJsonModuleWithFs(fs: vfs.FileSystem, configFile: string, allExpectedOutputs: ReadonlyArray, ...expectedDiagnosticMessages: fakes.ExpectedDiagnostic[]) { const host = new fakes.SolutionBuilderHost(fs); const builder = createSolutionBuilder(host, [configFile], { dry: false, force: false, verbose: false }); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages(...expectedDiagnosticMessages); if (!expectedDiagnosticMessages.length) { // Check for outputs. Not an exhaustive list - for (const output of allExpectedOutputs) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } + verifyOutputsPresent(fs, allExpectedOutputs); } } @@ -64,20 +62,18 @@ export default hello.hello`); const configFile = "src/tsconfig_withFiles.json"; replaceText(fs, configFile, `"composite": true,`, `"composite": true, "sourceMap": true,`); const host = new fakes.SolutionBuilderHost(fs); - const builder = createSolutionBuilder(host, [configFile], { verbose: true }); - builder.buildAllProjects(); + let builder = createSolutionBuilder(host, [configFile], { verbose: true }); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild(configFile), [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, configFile, "src/dist/src/index.js"], [Diagnostics.Building_project_0, `/${configFile}`] ); - for (const output of [...allExpectedOutputs, "/src/dist/src/index.js.map"]) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } + verifyOutputsPresent(fs, [...allExpectedOutputs, "/src/dist/src/index.js.map"]); host.clearDiagnostics(); - builder.resetBuildContext(); + builder = createSolutionBuilder(host, [configFile], { verbose: true }); tick(); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild(configFile), [Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, configFile, "src/src/index.ts", "src/dist/src/index.js"] @@ -89,20 +85,18 @@ export default hello.hello`); const configFile = "src/tsconfig_withFiles.json"; replaceText(fs, configFile, `"outDir": "dist",`, ""); const host = new fakes.SolutionBuilderHost(fs); - const builder = createSolutionBuilder(host, [configFile], { verbose: true }); - builder.buildAllProjects(); + let builder = createSolutionBuilder(host, [configFile], { verbose: true }); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild(configFile), [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, configFile, "src/src/index.js"], [Diagnostics.Building_project_0, `/${configFile}`] ); - for (const output of ["/src/src/index.js", "/src/src/index.d.ts"]) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } + verifyOutputsPresent(fs, ["/src/src/index.js", "/src/src/index.d.ts"]); host.clearDiagnostics(); - builder.resetBuildContext(); + builder = createSolutionBuilder(host, [configFile], { verbose: true }); tick(); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild(configFile), [Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, configFile, "src/src/index.ts", "src/src/index.js"] @@ -128,8 +122,8 @@ export default hello.hello`); const stringsConfigFile = "src/strings/tsconfig.json"; const mainConfigFile = "src/main/tsconfig.json"; const host = new fakes.SolutionBuilderHost(fs); - const builder = createSolutionBuilder(host, [configFile], { verbose: true }); - builder.buildAllProjects(); + let builder = createSolutionBuilder(host, [configFile], { verbose: true }); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild(stringsConfigFile, mainConfigFile, configFile), [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, stringsConfigFile, "src/strings/tsconfig.tsbuildinfo"], @@ -137,11 +131,11 @@ export default hello.hello`); [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, mainConfigFile, "src/main/index.js"], [Diagnostics.Building_project_0, `/${mainConfigFile}`], ); - assert(fs.existsSync(expectedOutput), `Expect file ${expectedOutput} to exist`); + verifyOutputsPresent(fs, [expectedOutput]); host.clearDiagnostics(); - builder.resetBuildContext(); + builder = createSolutionBuilder(host, [configFile], { verbose: true }); tick(); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild(stringsConfigFile, mainConfigFile, configFile), [Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, stringsConfigFile, "src/strings/foo.json", "src/strings/tsconfig.tsbuildinfo"], diff --git a/src/testRunner/unittests/tsbuild/sample.ts b/src/testRunner/unittests/tsbuild/sample.ts index 5ad63d76dc7..df2fb62db25 100644 --- a/src/testRunner/unittests/tsbuild/sample.ts +++ b/src/testRunner/unittests/tsbuild/sample.ts @@ -2,9 +2,10 @@ namespace ts { describe("unittests:: tsbuild:: on 'sample1' project", () => { let projFs: vfs.FileSystem; const { time, tick } = getTime(); - const allExpectedOutputs = ["/src/tests/index.js", - "/src/core/index.js", "/src/core/index.d.ts", "/src/core/index.d.ts.map", - "/src/logic/index.js", "/src/logic/index.js.map", "/src/logic/index.d.ts"]; + const testsOutputs = ["/src/tests/index.js", "/src/tests/index.d.ts", "/src/tests/tsconfig.tsbuildinfo"]; + const logicOutputs = ["/src/logic/index.js", "/src/logic/index.js.map", "/src/logic/index.d.ts", "/src/logic/tsconfig.tsbuildinfo"]; + const coreOutputs = ["/src/core/index.js", "/src/core/index.d.ts", "/src/core/index.d.ts.map", "/src/core/tsconfig.tsbuildinfo"]; + const allExpectedOutputs = [...testsOutputs, ...logicOutputs, ...coreOutputs]; before(() => { projFs = loadProjectFromDisk("tests/projects/sample1", time); @@ -21,13 +22,11 @@ namespace ts { const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false }); host.clearDiagnostics(); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages(/*empty*/); // Check for outputs. Not an exhaustive list - for (const output of allExpectedOutputs) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } + verifyOutputsPresent(fs, allExpectedOutputs); }); it("builds correctly when outDir is specified", () => { @@ -39,13 +38,11 @@ namespace ts { const host = new fakes.SolutionBuilderHost(fs); const builder = createSolutionBuilder(host, ["/src/tests"], {}); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages(/*empty*/); const expectedOutputs = allExpectedOutputs.map(f => f.replace("/logic/", "/logic/outDir/")); // Check for outputs. Not an exhaustive list - for (const output of expectedOutputs) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } + verifyOutputsPresent(fs, expectedOutputs); }); it("builds correctly when declarationDir is specified", () => { @@ -57,13 +54,11 @@ namespace ts { const host = new fakes.SolutionBuilderHost(fs); const builder = createSolutionBuilder(host, ["/src/tests"], {}); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages(/*empty*/); const expectedOutputs = allExpectedOutputs.map(f => f.replace("/logic/index.d.ts", "/logic/out/decls/index.d.ts")); // Check for outputs. Not an exhaustive list - for (const output of expectedOutputs) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } + verifyOutputsPresent(fs, expectedOutputs); }); it("builds correctly when project is not composite or doesnt have any references", () => { @@ -71,15 +66,13 @@ namespace ts { replaceText(fs, "/src/core/tsconfig.json", `"composite": true,`, ""); const host = new fakes.SolutionBuilderHost(fs); const builder = createSolutionBuilder(host, ["/src/core"], { verbose: true }); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json"), [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/core/tsconfig.json", "src/core/anotherModule.js"], [Diagnostics.Building_project_0, "/src/core/tsconfig.json"] ); - for (const output of ["/src/core/index.js", "/src/core/index.d.ts", "/src/core/index.d.ts.map"]) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } + verifyOutputsPresent(fs, ["/src/core/index.js", "/src/core/index.d.ts", "/src/core/index.d.ts.map"]); }); }); @@ -88,7 +81,7 @@ namespace ts { const fs = projFs.shadow(); const host = new fakes.SolutionBuilderHost(fs); const builder = createSolutionBuilder(host, ["/src/tests"], { dry: true, force: false, verbose: false }); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( [Diagnostics.A_non_dry_build_would_build_project_0, "/src/core/tsconfig.json"], [Diagnostics.A_non_dry_build_would_build_project_0, "/src/logic/tsconfig.json"], @@ -96,9 +89,7 @@ namespace ts { ); // Check for outputs to not be written. Not an exhaustive list - for (const output of allExpectedOutputs) { - assert(!fs.existsSync(output), `Expect file ${output} to not exist`); - } + verifyOutputsAbsent(fs, allExpectedOutputs); }); it("indicates that it would skip builds during a dry build", () => { @@ -106,12 +97,12 @@ namespace ts { const host = new fakes.SolutionBuilderHost(fs); let builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false }); - builder.buildAllProjects(); + builder.build(); tick(); host.clearDiagnostics(); builder = createSolutionBuilder(host, ["/src/tests"], { dry: true, force: false, verbose: false }); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( [Diagnostics.Project_0_is_up_to_date, "/src/core/tsconfig.json"], [Diagnostics.Project_0_is_up_to_date, "/src/logic/tsconfig.json"], @@ -126,18 +117,44 @@ namespace ts { const host = new fakes.SolutionBuilderHost(fs); const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false }); - builder.buildAllProjects(); + builder.build(); // Verify they exist - for (const output of allExpectedOutputs) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } - builder.cleanAllProjects(); + verifyOutputsPresent(fs, allExpectedOutputs); + + builder.clean(); // Verify they are gone - for (const output of allExpectedOutputs) { - assert(!fs.existsSync(output), `Expect file ${output} to not exist`); - } + verifyOutputsAbsent(fs, allExpectedOutputs); + // Subsequent clean shouldn't throw / etc - builder.cleanAllProjects(); + builder.clean(); + verifyOutputsAbsent(fs, allExpectedOutputs); + + builder.build(); + // Verify they exist + verifyOutputsPresent(fs, allExpectedOutputs); + }); + + it("cleans till project specified", () => { + const fs = projFs.shadow(); + const host = new fakes.SolutionBuilderHost(fs); + const builder = createSolutionBuilder(host, ["/src/tests"], {}); + builder.build(); + const result = builder.clean("/src/logic"); + host.assertDiagnosticMessages(/*empty*/); + verifyOutputsPresent(fs, testsOutputs); + verifyOutputsAbsent(fs, [...logicOutputs, ...coreOutputs]); + assert.equal(result, ExitStatus.Success); + }); + + it("cleaning project in not build order doesnt throw error", () => { + const fs = projFs.shadow(); + const host = new fakes.SolutionBuilderHost(fs); + const builder = createSolutionBuilder(host, ["/src/tests"], {}); + builder.build(); + const result = builder.clean("/src/logic2"); + host.assertDiagnosticMessages(/*empty*/); + verifyOutputsPresent(fs, allExpectedOutputs); + assert.equal(result, ExitStatus.InvalidProject_OutputsSkipped); }); }); @@ -146,15 +163,16 @@ namespace ts { const fs = projFs.shadow(); const host = new fakes.SolutionBuilderHost(fs); - const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: true, verbose: false }); - builder.buildAllProjects(); + let builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: true, verbose: false }); + builder.build(); let currentTime = time(); checkOutputTimestamps(currentTime); tick(); Debug.assert(time() !== currentTime, "Time moves on"); currentTime = time(); - builder.buildAllProjects(); + builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: true, verbose: false }); + builder.build(); checkOutputTimestamps(currentTime); function checkOutputTimestamps(expected: number) { @@ -171,11 +189,11 @@ namespace ts { function initializeWithBuild(opts?: BuildOptions) { const fs = projFs.shadow(); const host = new fakes.SolutionBuilderHost(fs); - const builder = createSolutionBuilder(host, ["/src/tests"], { verbose: true }); - builder.buildAllProjects(); + let builder = createSolutionBuilder(host, ["/src/tests"], { verbose: true }); + builder.build(); host.clearDiagnostics(); tick(); - builder.resetBuildContext(opts ? { ...opts, verbose: true } : undefined); + builder = createSolutionBuilder(host, ["/src/tests"], { ...(opts || {}), verbose: true }); return { fs, host, builder }; } @@ -183,8 +201,7 @@ namespace ts { const fs = projFs.shadow(); const host = new fakes.SolutionBuilderHost(fs); const builder = createSolutionBuilder(host, ["/src/tests"], { verbose: true }); - builder.resetBuildContext(); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json", "src/tests/tsconfig.json"), [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/core/tsconfig.json", "src/core/anotherModule.js"], @@ -199,7 +216,7 @@ namespace ts { // All three projects are up to date it("Detects that all projects are up to date", () => { const { host, builder } = initializeWithBuild(); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json", "src/tests/tsconfig.json"), [Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, "src/core/tsconfig.json", "src/core/anotherModule.ts", "src/core/anotherModule.js"], @@ -212,7 +229,7 @@ namespace ts { it("Only builds the leaf node project", () => { const { fs, host, builder } = initializeWithBuild(); fs.writeFileSync("/src/tests/index.ts", "const m = 10;"); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json", "src/tests/tsconfig.json"), [Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, "src/core/tsconfig.json", "src/core/anotherModule.ts", "src/core/anotherModule.js"], @@ -226,7 +243,7 @@ namespace ts { it("Detects type-only changes in upstream projects", () => { const { fs, host, builder } = initializeWithBuild(); replaceText(fs, "/src/core/index.ts", "HELLO WORLD", "WELCOME PLANET"); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json", "src/tests/tsconfig.json"), @@ -243,7 +260,7 @@ namespace ts { it("rebuilds completely when version in tsbuildinfo doesnt match ts version", () => { const { host, builder } = initializeWithBuild(); changeCompilerVersion(host); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json", "src/tests/tsconfig.json"), [Diagnostics.Project_0_is_out_of_date_because_output_for_it_was_generated_with_version_1_that_differs_with_current_version_2, "src/core/tsconfig.json", fakes.version, version], @@ -255,9 +272,38 @@ namespace ts { ); }); + it("does not rebuild if there is no program and bundle in the ts build info event if version doesnt match ts version", () => { + const fs = projFs.shadow(); + const host = new fakes.SolutionBuilderHost(fs, /*options*/ undefined, /*setParentNodes*/ undefined, createAbstractBuilder); + let builder = createSolutionBuilder(host, ["/src/tests"], { verbose: true }); + builder.build(); + host.assertDiagnosticMessages( + getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json", "src/tests/tsconfig.json"), + [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/core/tsconfig.json", "src/core/anotherModule.js"], + [Diagnostics.Building_project_0, "/src/core/tsconfig.json"], + [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/logic/tsconfig.json", "src/logic/index.js"], + [Diagnostics.Building_project_0, "/src/logic/tsconfig.json"], + [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/tests/tsconfig.json", "src/tests/index.js"], + [Diagnostics.Building_project_0, "/src/tests/tsconfig.json"] + ); + verifyOutputsPresent(fs, allExpectedOutputs); + + host.clearDiagnostics(); + tick(); + builder = createSolutionBuilder(host, ["/src/tests"], { verbose: true }); + changeCompilerVersion(host); + builder.build(); + host.assertDiagnosticMessages( + getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json", "src/tests/tsconfig.json"), + [Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, "src/core/tsconfig.json", "src/core/anotherModule.ts", "src/core/anotherModule.js"], + [Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, "src/logic/tsconfig.json", "src/logic/index.ts", "src/logic/index.js"], + [Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, "src/tests/tsconfig.json", "src/tests/index.ts", "src/tests/index.js"] + ); + }); + it("rebuilds from start if --f is passed", () => { const { host, builder } = initializeWithBuild({ force: true }); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json", "src/tests/tsconfig.json"), [Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, "src/core/tsconfig.json", "src/core/anotherModule.ts", "src/core/anotherModule.js"], @@ -272,7 +318,7 @@ namespace ts { it("rebuilds when tsconfig changes", () => { const { fs, host, builder } = initializeWithBuild(); replaceText(fs, "/src/tests/tsconfig.json", `"composite": true`, `"composite": true, "target": "es3"`); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json", "src/tests/tsconfig.json"), [Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, "src/core/tsconfig.json", "src/core/anotherModule.ts", "src/core/anotherModule.js"], @@ -287,8 +333,8 @@ namespace ts { fs.writeFileSync("/src/tests/tsconfig.base.json", JSON.stringify({ compilerOptions: { target: "es3" } })); replaceText(fs, "/src/tests/tsconfig.json", `"references": [`, `"extends": "./tsconfig.base.json", "references": [`); const host = new fakes.SolutionBuilderHost(fs); - const builder = createSolutionBuilder(host, ["/src/tests"], { verbose: true }); - builder.buildAllProjects(); + let builder = createSolutionBuilder(host, ["/src/tests"], { verbose: true }); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json", "src/tests/tsconfig.json"), [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/core/tsconfig.json", "src/core/anotherModule.js"], @@ -300,9 +346,9 @@ namespace ts { ); host.clearDiagnostics(); tick(); - builder.resetBuildContext(); + builder = createSolutionBuilder(host, ["/src/tests"], { verbose: true }); fs.writeFileSync("/src/tests/tsconfig.base.json", JSON.stringify({ compilerOptions: {} })); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json", "src/tests/tsconfig.json"), [Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, "src/core/tsconfig.json", "src/core/anotherModule.ts", "src/core/anotherModule.js"], @@ -311,6 +357,82 @@ namespace ts { [Diagnostics.Building_project_0, "/src/tests/tsconfig.json"] ); }); + + it("builds till project specified", () => { + const fs = projFs.shadow(); + const host = new fakes.SolutionBuilderHost(fs); + const builder = createSolutionBuilder(host, ["/src/tests"], {}); + const result = builder.build("/src/logic"); + host.assertDiagnosticMessages(/*empty*/); + verifyOutputsAbsent(fs, testsOutputs); + verifyOutputsPresent(fs, [...logicOutputs, ...coreOutputs]); + assert.equal(result, ExitStatus.Success); + }); + + it("building project in not build order doesnt throw error", () => { + const fs = projFs.shadow(); + const host = new fakes.SolutionBuilderHost(fs); + const builder = createSolutionBuilder(host, ["/src/tests"], {}); + const result = builder.build("/src/logic2"); + host.assertDiagnosticMessages(/*empty*/); + verifyOutputsAbsent(fs, allExpectedOutputs); + assert.equal(result, ExitStatus.InvalidProject_OutputsSkipped); + }); + + it("building using getNextInvalidatedProject", () => { + interface SolutionBuilderResult { + project: ResolvedConfigFileName; + result: T; + } + + const fs = projFs.shadow(); + const host = new fakes.SolutionBuilderHost(fs); + const builder = createSolutionBuilder(host, ["/src/tests"], {}); + verifyBuildNextResult({ + project: "/src/core/tsconfig.json" as ResolvedConfigFileName, + result: ExitStatus.Success + }, coreOutputs, [...logicOutputs, ...testsOutputs]); + + verifyBuildNextResult({ + project: "/src/logic/tsconfig.json" as ResolvedConfigFileName, + result: ExitStatus.Success + }, [...coreOutputs, ...logicOutputs], testsOutputs); + + verifyBuildNextResult({ + project: "/src/tests/tsconfig.json" as ResolvedConfigFileName, + result: ExitStatus.Success + }, allExpectedOutputs, emptyArray); + + verifyBuildNextResult(/*expected*/ undefined, allExpectedOutputs, emptyArray); + + function verifyBuildNextResult( + expected: SolutionBuilderResult | undefined, + presentOutputs: readonly string[], + absentOutputs: readonly string[] + ) { + const project = builder.getNextInvalidatedProject(); + const result = project && project.done(); + assert.deepEqual(project && { project: project.project, result }, expected); + verifyOutputsPresent(fs, presentOutputs); + verifyOutputsAbsent(fs, absentOutputs); + } + }); + + it("building using buildReferencedProject", () => { + const fs = projFs.shadow(); + const host = new fakes.SolutionBuilderHost(fs); + const builder = createSolutionBuilder(host, ["/src/tests"], { verbose: true }); + builder.buildReferences("/src/tests"); + host.assertDiagnosticMessages( + getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json"), + [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/core/tsconfig.json", "src/core/anotherModule.js"], + [Diagnostics.Building_project_0, "/src/core/tsconfig.json"], + [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/logic/tsconfig.json", "src/logic/index.js"], + [Diagnostics.Building_project_0, "/src/logic/tsconfig.json"], + ); + verifyOutputsPresent(fs, [...coreOutputs, ...logicOutputs]); + verifyOutputsAbsent(fs, testsOutputs); + }); }); describe("downstream-blocked compilations", () => { @@ -321,7 +443,7 @@ namespace ts { // Induce an error in the middle project replaceText(fs, "/src/logic/index.ts", "c.multiply(10, 15)", `c.muitply()`); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages( getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json", "src/tests/tsconfig.json"), [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/core/tsconfig.json", "src/core/anotherModule.js"], @@ -341,7 +463,7 @@ namespace ts { const host = new fakes.SolutionBuilderHost(fs); const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false }); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages(/*empty*/); // Update a timestamp in the middle project @@ -354,7 +476,7 @@ namespace ts { originalWriteFile.call(fs, path, data, encoding); }; // Because we haven't reset the build context, the builder should assume there's nothing to do right now - const status = builder.getUpToDateStatusOfFile(builder.resolveProjectName("/src/logic")); + const status = builder.getUpToDateStatusOfProject("/src/logic"); assert.equal(status.type, UpToDateStatusType.UpToDate, "Project should be assumed to be up-to-date"); verifyInvalidation(/*expectedToWriteTests*/ false); @@ -366,8 +488,8 @@ export class cNew {}`); function verifyInvalidation(expectedToWriteTests: boolean) { // Rebuild this project tick(); - builder.invalidateProject("/src/logic"); - builder.buildInvalidatedProject(); + builder.invalidateProject("/src/logic/tsconfig.json" as ResolvedConfigFilePath); + builder.buildNextInvalidatedProject(); // The file should be updated assert.isTrue(writtenFiles.has("/src/logic/index.js"), "JS file should have been rebuilt"); assert.equal(fs.statSync("/src/logic/index.js").mtimeMs, time(), "JS file should have been rebuilt"); @@ -377,7 +499,7 @@ export class cNew {}`); // Build downstream projects should update 'tests', but not 'core' tick(); - builder.buildInvalidatedProject(); + builder.buildNextInvalidatedProject(); if (expectedToWriteTests) { assert.isTrue(writtenFiles.has("/src/tests/index.js"), "Downstream JS file should have been rebuilt"); } @@ -395,7 +517,7 @@ export class cNew {}`); const fs = projFs.shadow(); const host = new fakes.SolutionBuilderHost(fs); const builder = createSolutionBuilder(host, ["/src/tests"], { listFiles: true }); - builder.buildAllProjects(); + builder.build(); assert.deepEqual(host.traces, [ "/lib/lib.d.ts", "/src/core/anotherModule.ts", @@ -422,7 +544,7 @@ export class cNew {}`); const fs = projFs.shadow(); const host = new fakes.SolutionBuilderHost(fs); const builder = createSolutionBuilder(host, ["/src/tests"], { listEmittedFiles: true }); - builder.buildAllProjects(); + builder.build(); assert.deepEqual(host.traces, [ "TSFILE: /src/core/anotherModule.js", "TSFILE: /src/core/anotherModule.d.ts.map", diff --git a/src/testRunner/unittests/tsbuild/transitiveReferences.ts b/src/testRunner/unittests/tsbuild/transitiveReferences.ts index 30e28de8cde..614796b2a85 100644 --- a/src/testRunner/unittests/tsbuild/transitiveReferences.ts +++ b/src/testRunner/unittests/tsbuild/transitiveReferences.ts @@ -30,11 +30,9 @@ namespace ts { const host = new fakes.SolutionBuilderHost(fs); modifyDiskLayout(fs); const builder = createSolutionBuilder(host, ["/src/tsconfig.c.json"], { listFiles: true }); - builder.buildAllProjects(); + builder.build(); host.assertDiagnosticMessages(...expectedDiagnostics); - for (const output of allExpectedOutputs) { - assert(fs.existsSync(output), `Expect file ${output} to exist`); - } + verifyOutputsPresent(fs, allExpectedOutputs); assert.deepEqual(host.traces, expectedFileTraces); } diff --git a/src/testRunner/unittests/tsbuildWatchMode.ts b/src/testRunner/unittests/tsbuildWatchMode.ts index 005956a98ad..a630e28f1d8 100644 --- a/src/testRunner/unittests/tsbuildWatchMode.ts +++ b/src/testRunner/unittests/tsbuildWatchMode.ts @@ -17,14 +17,14 @@ namespace ts.tscWatch { } export function createSolutionBuilder(system: WatchedSystem, rootNames: ReadonlyArray, defaultOptions?: BuildOptions) { - const host = createSolutionBuilderWithWatchHost(system); - return ts.createSolutionBuilder(host, rootNames, defaultOptions || { watch: true }); + const host = createSolutionBuilderHost(system); + return ts.createSolutionBuilder(host, rootNames, defaultOptions || {}); } - function createSolutionBuilderWithWatch(host: TsBuildWatchSystem, rootNames: ReadonlyArray, defaultOptions?: BuildOptions) { - const solutionBuilder = createSolutionBuilder(host, rootNames, defaultOptions); - solutionBuilder.buildAllProjects(); - solutionBuilder.startWatching(); + function createSolutionBuilderWithWatch(system: TsBuildWatchSystem, rootNames: ReadonlyArray, defaultOptions?: BuildOptions) { + const host = createSolutionBuilderWithWatchHost(system); + const solutionBuilder = ts.createSolutionBuilderWithWatch(host, rootNames, defaultOptions || { watch: true }); + solutionBuilder.build(); return solutionBuilder; } @@ -143,6 +143,28 @@ namespace ts.tscWatch { createSolutionInWatchMode(allFiles); }); + it("verify building references watches only those projects", () => { + const system = createTsBuildWatchSystem(allFiles, { currentDirectory: projectsLocation }); + const host = createSolutionBuilderWithWatchHost(system); + const solutionBuilder = ts.createSolutionBuilderWithWatch(host, [`${project}/${SubProject.tests}`], { watch: true }); + solutionBuilder.buildReferences(`${project}/${SubProject.tests}`); + + checkWatchedFiles(system, testProjectExpectedWatchedFiles.slice(0, testProjectExpectedWatchedFiles.length - tests.length)); + checkWatchedDirectories(system, emptyArray, /*recursive*/ false); + checkWatchedDirectories(system, testProjectExpectedWatchedDirectoriesRecursive, /*recursive*/ true); + + checkOutputErrorsInitial(system, emptyArray); + const testOutput = getOutputStamps(system, SubProject.tests, "index"); + const outputFileStamps = getOutputFileStamps(system); + for (const stamp of outputFileStamps.slice(0, outputFileStamps.length - testOutput.length)) { + assert.isDefined(stamp[1], `${stamp[0]} expected to be present`); + } + for (const stamp of testOutput) { + assert.isUndefined(stamp[1], `${stamp[0]} expected to be missing`); + } + return system; + }); + describe("validates the changes and watched files", () => { const newFileWithoutExtension = "newFile"; const newFile: File = { @@ -607,7 +629,7 @@ let x: string = 10;`); // Build the composite project const host = createTsBuildWatchSystem(allFiles, { currentDirectory }); const solutionBuilder = createSolutionBuilder(host, [solutionBuilderconfig], {}); - solutionBuilder.buildAllProjects(); + solutionBuilder.build(); const outputFileStamps = getOutputFileStamps(host); for (const stamp of outputFileStamps) { assert.isDefined(stamp[1], `${stamp[0]} expected to be present`); @@ -676,7 +698,7 @@ let x: string = 10;`); } function verifyScenario( - edit: (host: TsBuildWatchSystem, solutionBuilder: SolutionBuilder) => void, + edit: (host: TsBuildWatchSystem, solutionBuilder: SolutionBuilder) => void, expectedFilesAfterEdit: ReadonlyArray ) { it("with tsc-watch", () => { @@ -721,8 +743,8 @@ let x: string = 10;`); host.writeFile(logic[1].path, `${logic[1].content} function foo() { }`); - solutionBuilder.invalidateProject(`${project}/${SubProject.logic}`); - solutionBuilder.buildInvalidatedProject(); + solutionBuilder.invalidateProject(logic[0].path.toLowerCase() as ResolvedConfigFilePath); + solutionBuilder.buildNextInvalidatedProject(); // not ideal, but currently because of d.ts but no new file is written // There will be timeout queued even though file contents are same @@ -734,8 +756,8 @@ function foo() { host.writeFile(logic[1].path, `${logic[1].content} export function gfoo() { }`); - solutionBuilder.invalidateProject(logic[0].path); - solutionBuilder.buildInvalidatedProject(); + solutionBuilder.invalidateProject(logic[0].path.toLowerCase() as ResolvedConfigFilePath); + solutionBuilder.buildNextInvalidatedProject(); }, expectedProgramFiles); }); @@ -745,8 +767,8 @@ export function gfoo() { compilerOptions: { composite: true, declaration: true, declarationDir: "decls" }, references: [{ path: "../core" }] })); - solutionBuilder.invalidateProject(logic[0].path, ConfigFileProgramReloadLevel.Full); - solutionBuilder.buildInvalidatedProject(); + solutionBuilder.invalidateProject(logic[0].path.toLowerCase() as ResolvedConfigFilePath, ConfigFileProgramReloadLevel.Full); + solutionBuilder.buildNextInvalidatedProject(); }, [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, projectFilePath(SubProject.logic, "decls/index.d.ts")]); }); }); @@ -899,7 +921,7 @@ export function gfoo() { } function verifyScenario( - edit: (host: TsBuildWatchSystem, solutionBuilder: SolutionBuilder) => void, + edit: (host: TsBuildWatchSystem, solutionBuilder: SolutionBuilder) => void, expectedEditErrors: ReadonlyArray, expectedProgramFiles: ReadonlyArray, expectedWatchedFiles: ReadonlyArray, @@ -965,8 +987,8 @@ export function gfoo() { host.writeFile(bTs.path, `${bTs.content} export function gfoo() { }`); - solutionBuilder.invalidateProject(bTsconfig.path); - solutionBuilder.buildInvalidatedProject(); + solutionBuilder.invalidateProject(bTsconfig.path.toLowerCase() as ResolvedConfigFilePath); + solutionBuilder.buildNextInvalidatedProject(); }, emptyArray, expectedProgramFiles, @@ -1140,9 +1162,7 @@ export function gfoo() { it("incremental updates in verbose mode", () => { const host = createTsBuildWatchSystem(allFiles, { currentDirectory: projectsLocation }); - const solutionBuilder = createSolutionBuilder(host, [`${project}/${SubProject.tests}`], { verbose: true, watch: true }); - solutionBuilder.buildAllProjects(); - solutionBuilder.startWatching(); + createSolutionBuilderWithWatch(host, [`${project}/${SubProject.tests}`], { verbose: true, watch: true }); checkOutputErrorsInitial(host, emptyArray, /*disableConsoleClears*/ undefined, [ `Projects in this build: \r\n * sample1/core/tsconfig.json\r\n * sample1/logic/tsconfig.json\r\n * sample1/tests/tsconfig.json\n\n`, `Project 'sample1/core/tsconfig.json' is out of date because output file 'sample1/core/anotherModule.js' does not exist\n\n`, diff --git a/src/testRunner/unittests/tscWatch/incremental.ts b/src/testRunner/unittests/tscWatch/incremental.ts index 35ec5bff555..54109dec846 100644 --- a/src/testRunner/unittests/tscWatch/incremental.ts +++ b/src/testRunner/unittests/tscWatch/incremental.ts @@ -105,9 +105,23 @@ namespace ts.tscWatch { result.close(); } + function sanitizeBuildInfo(content: string) { + const buildInfo = getBuildInfo(content); + fakes.sanitizeBuildInfoProgram(buildInfo); + return getBuildInfoText(buildInfo); + } + function checkFileEmit(actual: Map, expected: ReadonlyArray) { assert.equal(actual.size, expected.length, `Actual: ${JSON.stringify(arrayFrom(actual.entries()), /*replacer*/ undefined, " ")}\nExpected: ${JSON.stringify(expected, /*replacer*/ undefined, " ")}`); - expected.forEach(file => assert.equal(actual.get(file.path), file.content, `Emit for ${file.path}`)); + expected.forEach(file => { + let expectedContent = file.content; + let actualContent = actual.get(file.path); + if (isBuildInfoFile(file.path)) { + actualContent = actualContent && sanitizeBuildInfo(actualContent); + expectedContent = sanitizeBuildInfo(expectedContent); + } + assert.equal(actualContent, expectedContent, `Emit for ${file.path}`); + }); } const libFileInfo: BuilderState.FileInfo = { diff --git a/src/testRunner/unittests/tsserver/projectReferences.ts b/src/testRunner/unittests/tsserver/projectReferences.ts index af6e9d7281e..1dd11ba7cf1 100644 --- a/src/testRunner/unittests/tsserver/projectReferences.ts +++ b/src/testRunner/unittests/tsserver/projectReferences.ts @@ -5,7 +5,7 @@ namespace ts.projectSystem { // ts build should succeed const solutionBuilder = tscWatch.createSolutionBuilder(host, rootNames, {}); - solutionBuilder.buildAllProjects(); + solutionBuilder.build(); assert.equal(host.getOutput().length, 0); return host; diff --git a/src/testRunner/unittests/tsserver/projects.ts b/src/testRunner/unittests/tsserver/projects.ts index ba1eae236a5..409ce5c525f 100644 --- a/src/testRunner/unittests/tsserver/projects.ts +++ b/src/testRunner/unittests/tsserver/projects.ts @@ -1341,6 +1341,26 @@ var x = 10;` } }); + it("no project structure update on directory watch invoke on open file save", () => { + const projectRootPath = "/users/username/projects/project"; + const file1: File = { + path: `${projectRootPath}/a.ts`, + content: "export const a = 10;" + }; + const config: File = { + path: `${projectRootPath}/tsconfig.json`, + content: "{}" + }; + const files = [file1, config]; + const host = createServerHost(files); + const service = createProjectService(host); + service.openClientFile(file1.path); + checkNumberOfProjects(service, { configuredProjects: 1 }); + + host.modifyFile(file1.path, file1.content, { invokeFileDeleteCreateAsPartInsteadOfChange: true }); + host.checkTimeoutQueueLength(0); + }); + it("handles delayed directory watch invoke on file creation", () => { const projectRootPath = "/users/username/projects/project"; const fileB: File = { diff --git a/src/testRunner/unittests/tsserver/resolutionCache.ts b/src/testRunner/unittests/tsserver/resolutionCache.ts index 33b59e2faae..768111f3bfe 100644 --- a/src/testRunner/unittests/tsserver/resolutionCache.ts +++ b/src/testRunner/unittests/tsserver/resolutionCache.ts @@ -975,5 +975,34 @@ export const x = 10;` host.checkTimeoutQueueLength(0); }); }); + + describe("avoid unnecessary invalidation", () => { + it("unnecessary lookup invalidation on save", () => { + const expectedNonRelativeDirectories = [`${projectLocation}/node_modules`, `${projectLocation}/src`]; + const module1Name = "module1"; + const module2Name = "module2"; + const fileContent = `import { module1 } from "${module1Name}";import { module2 } from "${module2Name}";`; + const file1: File = { + path: `${projectLocation}/src/file1.ts`, + content: fileContent + }; + const { module1, module2 } = getModules(`${projectLocation}/src/node_modules/module1/index.ts`, `${projectLocation}/node_modules/module2/index.ts`); + const files = [module1, module2, file1, configFile, libFile]; + const host = createServerHost(files); + const resolutionTrace = createHostModuleResolutionTrace(host); + const service = createProjectService(host); + service.openClientFile(file1.path); + const project = service.configuredProjects.get(configFile.path)!; + (project as ResolutionCacheHost).maxNumberOfFilesToIterateForInvalidation = 1; + const expectedTrace = getExpectedNonRelativeModuleResolutionTrace(host, file1, module1, module1Name); + getExpectedNonRelativeModuleResolutionTrace(host, file1, module2, module2Name, expectedTrace); + verifyTrace(resolutionTrace, expectedTrace); + verifyWatchesWithConfigFile(host, files, file1, expectedNonRelativeDirectories); + + // invoke callback to simulate saving + host.modifyFile(file1.path, file1.content, { invokeFileDeleteCreateAsPartInsteadOfChange: true }); + host.checkTimeoutQueueLengthAndRun(0); + }); + }); }); } diff --git a/src/testRunner/unittests/tsserver/syntaxOperations.ts b/src/testRunner/unittests/tsserver/syntaxOperations.ts index 66a962d3625..d3127355191 100644 --- a/src/testRunner/unittests/tsserver/syntaxOperations.ts +++ b/src/testRunner/unittests/tsserver/syntaxOperations.ts @@ -60,13 +60,14 @@ describe("Test Suite 1", () => { const navBarResultUnitTest1 = navBarFull(session, unitTest1); host.deleteFile(unitTest1.path); - host.checkTimeoutQueueLengthAndRun(2); - checkProjectActualFiles(project, expectedFilesWithoutUnitTest1); + host.checkTimeoutQueueLengthAndRun(0); + checkProjectActualFiles(project, expectedFilesWithUnitTest1); session.executeCommandSeq({ command: protocol.CommandTypes.Close, arguments: { file: unitTest1.path } }); + host.checkTimeoutQueueLengthAndRun(2); checkProjectActualFiles(project, expectedFilesWithoutUnitTest1); const unitTest1WithChangedContent: File = { diff --git a/src/tsc/tsc.ts b/src/tsc/tsc.ts index 500480463bd..6a340109238 100644 --- a/src/tsc/tsc.ts +++ b/src/tsc/tsc.ts @@ -183,6 +183,9 @@ namespace ts { function performBuild(args: string[]) { const { buildOptions, projects, errors } = parseBuildCommand(args); + // Update to pretty if host supports it + updateReportDiagnostic(buildOptions); + if (errors.length > 0) { errors.forEach(reportDiagnostic); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); @@ -194,8 +197,6 @@ namespace ts { return sys.exit(ExitStatus.Success); } - // Update to pretty if host supports it - updateReportDiagnostic(buildOptions); if (projects.length === 0) { printVersion(); printHelp(buildOpts, "--build "); @@ -206,28 +207,22 @@ namespace ts { reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--build")); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } + if (buildOptions.watch) { reportWatchModeWithoutSysSupport(); + const buildHost = createSolutionBuilderWithWatchHost(sys, /*createProgram*/ undefined, reportDiagnostic, createBuilderStatusReporter(sys, shouldBePretty(buildOptions)), createWatchStatusReporter(buildOptions)); + updateCreateProgram(buildHost); + buildHost.afterProgramEmitAndDiagnostics = program => reportStatistics(program.getProgram()); + const builder = createSolutionBuilderWithWatch(buildHost, projects, buildOptions); + builder.build(); + return; } - // Use default createProgram - const buildHost = buildOptions.watch ? - createSolutionBuilderWithWatchHost(sys, /*createProgram*/ undefined, reportDiagnostic, createBuilderStatusReporter(sys, shouldBePretty(buildOptions)), createWatchStatusReporter(buildOptions)) : - createSolutionBuilderHost(sys, /*createProgram*/ undefined, reportDiagnostic, createBuilderStatusReporter(sys, shouldBePretty(buildOptions)), createReportErrorSummary(buildOptions)); + const buildHost = createSolutionBuilderHost(sys, /*createProgram*/ undefined, reportDiagnostic, createBuilderStatusReporter(sys, shouldBePretty(buildOptions)), createReportErrorSummary(buildOptions)); updateCreateProgram(buildHost); - buildHost.afterProgramEmitAndDiagnostics = (program: BuilderProgram) => reportStatistics(program.getProgram()); - + buildHost.afterProgramEmitAndDiagnostics = program => reportStatistics(program.getProgram()); const builder = createSolutionBuilder(buildHost, projects, buildOptions); - if (buildOptions.clean) { - return sys.exit(builder.cleanAllProjects()); - } - - if (buildOptions.watch) { - builder.buildAllProjects(); - return (builder as SolutionBuilderWithWatch).startWatching(); - } - - return sys.exit(builder.buildAllProjects()); + return sys.exit(buildOptions.clean ? builder.clean() : builder.build()); } function createReportErrorSummary(options: CompilerOptions | BuildOptions): ReportEmitErrorSummary | undefined { @@ -251,7 +246,7 @@ namespace ts { configFileParsingDiagnostics }; const program = createProgram(programOptions); - const exitStatus = emitFilesAndReportErrors( + const exitStatus = emitFilesAndReportErrorsAndGetExitStatus( program, reportDiagnostic, s => sys.write(s + sys.newLine), diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index d2db2d24b0d..00aa557ba19 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -14,7 +14,7 @@ and limitations under the License. ***************************************************************************** */ declare namespace ts { - const versionMajorMinor = "3.5"; + const versionMajorMinor = "3.6"; /** The version of the TypeScript compiler release */ const version: string; } @@ -1910,7 +1910,8 @@ declare namespace ts { enum ExitStatus { Success = 0, DiagnosticsPresent_OutputsSkipped = 1, - DiagnosticsPresent_OutputsGenerated = 2 + DiagnosticsPresent_OutputsGenerated = 2, + InvalidProject_OutputsSkipped = 3 } interface EmitResult { emitSkipped: boolean; @@ -1969,6 +1970,7 @@ declare namespace ts { */ getExportSymbolOfSymbol(symbol: Symbol): Symbol; getPropertySymbolOfDestructuringAssignment(location: Identifier): Symbol | undefined; + getTypeOfAssignmentPattern(pattern: AssignmentPattern): Type; getTypeAtLocation(node: Node): Type; getTypeFromTypeNode(node: TypeNode): Type; signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): string; @@ -4422,7 +4424,7 @@ declare namespace ts { * The builder that can handle the changes in program and iterate through changed file to emit the files * The semantic diagnostics are cached per file and managed by clearing for the changed/affected files */ - interface EmitAndSemanticDiagnosticsBuilderProgram extends BuilderProgram { + interface EmitAndSemanticDiagnosticsBuilderProgram extends SemanticDiagnosticsBuilderProgram { /** * Emits the next affected file's emit result (EmitResult and sourceFiles emitted) or returns undefined if iteration is complete * The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host @@ -4448,6 +4450,17 @@ declare namespace ts { function createAbstractBuilder(rootNames: ReadonlyArray | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray, projectReferences?: ReadonlyArray): BuilderProgram; } declare namespace ts { + function readBuilderProgram(compilerOptions: CompilerOptions, readFile: (path: string) => string | undefined): EmitAndSemanticDiagnosticsBuilderProgram | undefined; + function createIncrementalCompilerHost(options: CompilerOptions, system?: System): CompilerHost; + interface IncrementalProgramOptions { + rootNames: ReadonlyArray; + options: CompilerOptions; + configFileParsingDiagnostics?: ReadonlyArray; + projectReferences?: ReadonlyArray; + host?: CompilerHost; + createProgram?: CreateProgram; + } + function createIncrementalProgram({ rootNames, options, configFileParsingDiagnostics, projectReferences, host, createProgram }: IncrementalProgramOptions): T; type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void; /** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */ type CreateProgram = (rootNames: ReadonlyArray | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray, projectReferences?: ReadonlyArray | undefined) => T; @@ -4561,6 +4574,91 @@ declare namespace ts { */ function createWatchProgram(host: WatchCompilerHostOfConfigFile): WatchOfConfigFile; } +declare namespace ts { + interface BuildOptions { + dry?: boolean; + force?: boolean; + verbose?: boolean; + incremental?: boolean; + traceResolution?: boolean; + [option: string]: CompilerOptionsValue | undefined; + } + type ReportEmitErrorSummary = (errorCount: number) => void; + interface SolutionBuilderHostBase extends ProgramHost { + createDirectory?(path: string): void; + /** + * Should provide create directory and writeFile if done of invalidatedProjects is not invoked with + * writeFileCallback + */ + writeFile?(path: string, data: string, writeByteOrderMark?: boolean): void; + getModifiedTime(fileName: string): Date | undefined; + setModifiedTime(fileName: string, date: Date): void; + deleteFile(fileName: string): void; + getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined; + reportDiagnostic: DiagnosticReporter; + reportSolutionBuilderStatus: DiagnosticReporter; + afterProgramEmitAndDiagnostics?(program: T): void; + } + interface SolutionBuilderHost extends SolutionBuilderHostBase { + reportErrorSummary?: ReportEmitErrorSummary; + } + interface SolutionBuilderWithWatchHost extends SolutionBuilderHostBase, WatchHost { + } + interface SolutionBuilder { + build(project?: string, cancellationToken?: CancellationToken): ExitStatus; + clean(project?: string): ExitStatus; + buildReferences(project: string, cancellationToken?: CancellationToken): ExitStatus; + cleanReferences(project?: string): ExitStatus; + getNextInvalidatedProject(cancellationToken?: CancellationToken): InvalidatedProject | undefined; + } + /** + * Create a function that reports watch status by writing to the system and handles the formating of the diagnostic + */ + function createBuilderStatusReporter(system: System, pretty?: boolean): DiagnosticReporter; + function createSolutionBuilderHost(system?: System, createProgram?: CreateProgram, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter, reportErrorSummary?: ReportEmitErrorSummary): SolutionBuilderHost; + function createSolutionBuilderWithWatchHost(system?: System, createProgram?: CreateProgram, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): SolutionBuilderWithWatchHost; + function createSolutionBuilder(host: SolutionBuilderHost, rootNames: ReadonlyArray, defaultOptions: BuildOptions): SolutionBuilder; + function createSolutionBuilderWithWatch(host: SolutionBuilderWithWatchHost, rootNames: ReadonlyArray, defaultOptions: BuildOptions): SolutionBuilder; + enum InvalidatedProjectKind { + Build = 0, + UpdateBundle = 1, + UpdateOutputFileStamps = 2 + } + interface InvalidatedProjectBase { + readonly kind: InvalidatedProjectKind; + readonly project: ResolvedConfigFileName; + /** + * To dispose this project and ensure that all the necessary actions are taken and state is updated accordingly + */ + done(cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, customTransformers?: CustomTransformers): ExitStatus; + getCompilerOptions(): CompilerOptions; + getCurrentDirectory(): string; + } + interface UpdateOutputFileStampsProject extends InvalidatedProjectBase { + readonly kind: InvalidatedProjectKind.UpdateOutputFileStamps; + updateOutputFileStatmps(): void; + } + interface BuildInvalidedProject extends InvalidatedProjectBase { + readonly kind: InvalidatedProjectKind.Build; + getBuilderProgram(): T | undefined; + getProgram(): Program | undefined; + getSourceFile(fileName: string): SourceFile | undefined; + getSourceFiles(): ReadonlyArray; + getOptionsDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray; + getGlobalDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray; + getConfigFileParsingDiagnostics(): ReadonlyArray; + getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray; + getAllDependencies(sourceFile: SourceFile): ReadonlyArray; + getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray; + getSemanticDiagnosticsOfNextAffectedFile(cancellationToken?: CancellationToken, ignoreSourceFile?: (sourceFile: SourceFile) => boolean): AffectedFileResult>; + emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult | undefined; + } + interface UpdateBundleProject extends InvalidatedProjectBase { + readonly kind: InvalidatedProjectKind.UpdateBundle; + emit(writeFile?: WriteFileCallback, customTransformers?: CustomTransformers): EmitResult | BuildInvalidedProject | undefined; + } + type InvalidatedProject = UpdateOutputFileStampsProject | BuildInvalidedProject | UpdateBundleProject; +} declare namespace ts.server { type ActionSet = "action::set"; type ActionInvalidate = "action::invalidate"; @@ -8333,7 +8431,7 @@ declare namespace ts.server { private readonly cancellationToken; isNonTsProject(): boolean; isJsOnlyProject(): boolean; - static resolveModule(moduleName: string, initialDir: string, host: ServerHost, log: (message: string) => void): {} | undefined; + static resolveModule(moduleName: string, initialDir: string, host: ServerHost, log: (message: string) => void, logErrors?: (message: string) => void): {} | undefined; isKnownTypesPackageName(name: string): boolean; installPackage(options: InstallPackageOptions): Promise; private readonly typingsCache; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 9b560c0ef09..bb98c6a873f 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -14,7 +14,7 @@ and limitations under the License. ***************************************************************************** */ declare namespace ts { - const versionMajorMinor = "3.5"; + const versionMajorMinor = "3.6"; /** The version of the TypeScript compiler release */ const version: string; } @@ -1910,7 +1910,8 @@ declare namespace ts { enum ExitStatus { Success = 0, DiagnosticsPresent_OutputsSkipped = 1, - DiagnosticsPresent_OutputsGenerated = 2 + DiagnosticsPresent_OutputsGenerated = 2, + InvalidProject_OutputsSkipped = 3 } interface EmitResult { emitSkipped: boolean; @@ -1969,6 +1970,7 @@ declare namespace ts { */ getExportSymbolOfSymbol(symbol: Symbol): Symbol; getPropertySymbolOfDestructuringAssignment(location: Identifier): Symbol | undefined; + getTypeOfAssignmentPattern(pattern: AssignmentPattern): Type; getTypeAtLocation(node: Node): Type; getTypeFromTypeNode(node: TypeNode): Type; signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): string; @@ -4422,7 +4424,7 @@ declare namespace ts { * The builder that can handle the changes in program and iterate through changed file to emit the files * The semantic diagnostics are cached per file and managed by clearing for the changed/affected files */ - interface EmitAndSemanticDiagnosticsBuilderProgram extends BuilderProgram { + interface EmitAndSemanticDiagnosticsBuilderProgram extends SemanticDiagnosticsBuilderProgram { /** * Emits the next affected file's emit result (EmitResult and sourceFiles emitted) or returns undefined if iteration is complete * The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host @@ -4448,6 +4450,17 @@ declare namespace ts { function createAbstractBuilder(rootNames: ReadonlyArray | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray, projectReferences?: ReadonlyArray): BuilderProgram; } declare namespace ts { + function readBuilderProgram(compilerOptions: CompilerOptions, readFile: (path: string) => string | undefined): EmitAndSemanticDiagnosticsBuilderProgram | undefined; + function createIncrementalCompilerHost(options: CompilerOptions, system?: System): CompilerHost; + interface IncrementalProgramOptions { + rootNames: ReadonlyArray; + options: CompilerOptions; + configFileParsingDiagnostics?: ReadonlyArray; + projectReferences?: ReadonlyArray; + host?: CompilerHost; + createProgram?: CreateProgram; + } + function createIncrementalProgram({ rootNames, options, configFileParsingDiagnostics, projectReferences, host, createProgram }: IncrementalProgramOptions): T; type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void; /** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */ type CreateProgram = (rootNames: ReadonlyArray | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray, projectReferences?: ReadonlyArray | undefined) => T; @@ -4561,6 +4574,91 @@ declare namespace ts { */ function createWatchProgram(host: WatchCompilerHostOfConfigFile): WatchOfConfigFile; } +declare namespace ts { + interface BuildOptions { + dry?: boolean; + force?: boolean; + verbose?: boolean; + incremental?: boolean; + traceResolution?: boolean; + [option: string]: CompilerOptionsValue | undefined; + } + type ReportEmitErrorSummary = (errorCount: number) => void; + interface SolutionBuilderHostBase extends ProgramHost { + createDirectory?(path: string): void; + /** + * Should provide create directory and writeFile if done of invalidatedProjects is not invoked with + * writeFileCallback + */ + writeFile?(path: string, data: string, writeByteOrderMark?: boolean): void; + getModifiedTime(fileName: string): Date | undefined; + setModifiedTime(fileName: string, date: Date): void; + deleteFile(fileName: string): void; + getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined; + reportDiagnostic: DiagnosticReporter; + reportSolutionBuilderStatus: DiagnosticReporter; + afterProgramEmitAndDiagnostics?(program: T): void; + } + interface SolutionBuilderHost extends SolutionBuilderHostBase { + reportErrorSummary?: ReportEmitErrorSummary; + } + interface SolutionBuilderWithWatchHost extends SolutionBuilderHostBase, WatchHost { + } + interface SolutionBuilder { + build(project?: string, cancellationToken?: CancellationToken): ExitStatus; + clean(project?: string): ExitStatus; + buildReferences(project: string, cancellationToken?: CancellationToken): ExitStatus; + cleanReferences(project?: string): ExitStatus; + getNextInvalidatedProject(cancellationToken?: CancellationToken): InvalidatedProject | undefined; + } + /** + * Create a function that reports watch status by writing to the system and handles the formating of the diagnostic + */ + function createBuilderStatusReporter(system: System, pretty?: boolean): DiagnosticReporter; + function createSolutionBuilderHost(system?: System, createProgram?: CreateProgram, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter, reportErrorSummary?: ReportEmitErrorSummary): SolutionBuilderHost; + function createSolutionBuilderWithWatchHost(system?: System, createProgram?: CreateProgram, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): SolutionBuilderWithWatchHost; + function createSolutionBuilder(host: SolutionBuilderHost, rootNames: ReadonlyArray, defaultOptions: BuildOptions): SolutionBuilder; + function createSolutionBuilderWithWatch(host: SolutionBuilderWithWatchHost, rootNames: ReadonlyArray, defaultOptions: BuildOptions): SolutionBuilder; + enum InvalidatedProjectKind { + Build = 0, + UpdateBundle = 1, + UpdateOutputFileStamps = 2 + } + interface InvalidatedProjectBase { + readonly kind: InvalidatedProjectKind; + readonly project: ResolvedConfigFileName; + /** + * To dispose this project and ensure that all the necessary actions are taken and state is updated accordingly + */ + done(cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, customTransformers?: CustomTransformers): ExitStatus; + getCompilerOptions(): CompilerOptions; + getCurrentDirectory(): string; + } + interface UpdateOutputFileStampsProject extends InvalidatedProjectBase { + readonly kind: InvalidatedProjectKind.UpdateOutputFileStamps; + updateOutputFileStatmps(): void; + } + interface BuildInvalidedProject extends InvalidatedProjectBase { + readonly kind: InvalidatedProjectKind.Build; + getBuilderProgram(): T | undefined; + getProgram(): Program | undefined; + getSourceFile(fileName: string): SourceFile | undefined; + getSourceFiles(): ReadonlyArray; + getOptionsDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray; + getGlobalDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray; + getConfigFileParsingDiagnostics(): ReadonlyArray; + getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray; + getAllDependencies(sourceFile: SourceFile): ReadonlyArray; + getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray; + getSemanticDiagnosticsOfNextAffectedFile(cancellationToken?: CancellationToken, ignoreSourceFile?: (sourceFile: SourceFile) => boolean): AffectedFileResult>; + emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult | undefined; + } + interface UpdateBundleProject extends InvalidatedProjectBase { + readonly kind: InvalidatedProjectKind.UpdateBundle; + emit(writeFile?: WriteFileCallback, customTransformers?: CustomTransformers): EmitResult | BuildInvalidedProject | undefined; + } + type InvalidatedProject = UpdateOutputFileStampsProject | BuildInvalidedProject | UpdateBundleProject; +} declare namespace ts.server { type ActionSet = "action::set"; type ActionInvalidate = "action::invalidate"; diff --git a/tests/baselines/reference/contravariantTypeAliasInference.js b/tests/baselines/reference/contravariantTypeAliasInference.js new file mode 100644 index 00000000000..a0a7b45db91 --- /dev/null +++ b/tests/baselines/reference/contravariantTypeAliasInference.js @@ -0,0 +1,25 @@ +//// [contravariantTypeAliasInference.ts] +type Func1 = (x: T) => void; +type Func2 = ((x: T) => void) | undefined; + +declare let f1: Func1; +declare let f2: Func1<"a">; + +declare function foo(f1: Func1, f2: Func1): void; + +foo(f1, f2); + +declare let g1: Func2; +declare let g2: Func2<"a">; + +declare function bar(g1: Func2, g2: Func2): void; + +bar(f1, f2); +bar(g1, g2); + + +//// [contravariantTypeAliasInference.js] +"use strict"; +foo(f1, f2); +bar(f1, f2); +bar(g1, g2); diff --git a/tests/baselines/reference/contravariantTypeAliasInference.symbols b/tests/baselines/reference/contravariantTypeAliasInference.symbols new file mode 100644 index 00000000000..ff34d3ea17e --- /dev/null +++ b/tests/baselines/reference/contravariantTypeAliasInference.symbols @@ -0,0 +1,64 @@ +=== tests/cases/compiler/contravariantTypeAliasInference.ts === +type Func1 = (x: T) => void; +>Func1 : Symbol(Func1, Decl(contravariantTypeAliasInference.ts, 0, 0)) +>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 0, 11)) +>x : Symbol(x, Decl(contravariantTypeAliasInference.ts, 0, 17)) +>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 0, 11)) + +type Func2 = ((x: T) => void) | undefined; +>Func2 : Symbol(Func2, Decl(contravariantTypeAliasInference.ts, 0, 31)) +>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 1, 11)) +>x : Symbol(x, Decl(contravariantTypeAliasInference.ts, 1, 18)) +>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 1, 11)) + +declare let f1: Func1; +>f1 : Symbol(f1, Decl(contravariantTypeAliasInference.ts, 3, 11)) +>Func1 : Symbol(Func1, Decl(contravariantTypeAliasInference.ts, 0, 0)) + +declare let f2: Func1<"a">; +>f2 : Symbol(f2, Decl(contravariantTypeAliasInference.ts, 4, 11)) +>Func1 : Symbol(Func1, Decl(contravariantTypeAliasInference.ts, 0, 0)) + +declare function foo(f1: Func1, f2: Func1): void; +>foo : Symbol(foo, Decl(contravariantTypeAliasInference.ts, 4, 27)) +>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 6, 21)) +>f1 : Symbol(f1, Decl(contravariantTypeAliasInference.ts, 6, 24)) +>Func1 : Symbol(Func1, Decl(contravariantTypeAliasInference.ts, 0, 0)) +>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 6, 21)) +>f2 : Symbol(f2, Decl(contravariantTypeAliasInference.ts, 6, 37)) +>Func1 : Symbol(Func1, Decl(contravariantTypeAliasInference.ts, 0, 0)) +>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 6, 21)) + +foo(f1, f2); +>foo : Symbol(foo, Decl(contravariantTypeAliasInference.ts, 4, 27)) +>f1 : Symbol(f1, Decl(contravariantTypeAliasInference.ts, 3, 11)) +>f2 : Symbol(f2, Decl(contravariantTypeAliasInference.ts, 4, 11)) + +declare let g1: Func2; +>g1 : Symbol(g1, Decl(contravariantTypeAliasInference.ts, 10, 11)) +>Func2 : Symbol(Func2, Decl(contravariantTypeAliasInference.ts, 0, 31)) + +declare let g2: Func2<"a">; +>g2 : Symbol(g2, Decl(contravariantTypeAliasInference.ts, 11, 11)) +>Func2 : Symbol(Func2, Decl(contravariantTypeAliasInference.ts, 0, 31)) + +declare function bar(g1: Func2, g2: Func2): void; +>bar : Symbol(bar, Decl(contravariantTypeAliasInference.ts, 11, 27)) +>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 13, 21)) +>g1 : Symbol(g1, Decl(contravariantTypeAliasInference.ts, 13, 24)) +>Func2 : Symbol(Func2, Decl(contravariantTypeAliasInference.ts, 0, 31)) +>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 13, 21)) +>g2 : Symbol(g2, Decl(contravariantTypeAliasInference.ts, 13, 37)) +>Func2 : Symbol(Func2, Decl(contravariantTypeAliasInference.ts, 0, 31)) +>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 13, 21)) + +bar(f1, f2); +>bar : Symbol(bar, Decl(contravariantTypeAliasInference.ts, 11, 27)) +>f1 : Symbol(f1, Decl(contravariantTypeAliasInference.ts, 3, 11)) +>f2 : Symbol(f2, Decl(contravariantTypeAliasInference.ts, 4, 11)) + +bar(g1, g2); +>bar : Symbol(bar, Decl(contravariantTypeAliasInference.ts, 11, 27)) +>g1 : Symbol(g1, Decl(contravariantTypeAliasInference.ts, 10, 11)) +>g2 : Symbol(g2, Decl(contravariantTypeAliasInference.ts, 11, 11)) + diff --git a/tests/baselines/reference/contravariantTypeAliasInference.types b/tests/baselines/reference/contravariantTypeAliasInference.types new file mode 100644 index 00000000000..9ff197cdfce --- /dev/null +++ b/tests/baselines/reference/contravariantTypeAliasInference.types @@ -0,0 +1,49 @@ +=== tests/cases/compiler/contravariantTypeAliasInference.ts === +type Func1 = (x: T) => void; +>Func1 : Func1 +>x : T + +type Func2 = ((x: T) => void) | undefined; +>Func2 : Func2 +>x : T + +declare let f1: Func1; +>f1 : Func1 + +declare let f2: Func1<"a">; +>f2 : Func1<"a"> + +declare function foo(f1: Func1, f2: Func1): void; +>foo : (f1: Func1, f2: Func1) => void +>f1 : Func1 +>f2 : Func1 + +foo(f1, f2); +>foo(f1, f2) : void +>foo : (f1: Func1, f2: Func1) => void +>f1 : Func1 +>f2 : Func1<"a"> + +declare let g1: Func2; +>g1 : Func2 + +declare let g2: Func2<"a">; +>g2 : Func2<"a"> + +declare function bar(g1: Func2, g2: Func2): void; +>bar : (g1: Func2, g2: Func2) => void +>g1 : Func2 +>g2 : Func2 + +bar(f1, f2); +>bar(f1, f2) : void +>bar : (g1: Func2, g2: Func2) => void +>f1 : Func1 +>f2 : Func1<"a"> + +bar(g1, g2); +>bar(g1, g2) : void +>bar : (g1: Func2, g2: Func2) => void +>g1 : Func2 +>g2 : Func2<"a"> + diff --git a/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink.js b/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink.js new file mode 100644 index 00000000000..00efdd49280 --- /dev/null +++ b/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink.js @@ -0,0 +1,45 @@ +//// [tests/cases/compiler/declarationEmitForGlobalishSpecifierSymlink.ts] //// + +//// [impl.d.ts] +export function getA(): A; +export enum A { + Val +} +//// [index.d.ts] +export * from "./src/impl"; +//// [package.json] +{ + "name": "typescript-fsa", + "version": "1.0.0" +} +//// [impl.d.ts] +export function getA(): A; +export enum A { + Val +} +//// [index.d.ts] +export * from "./src/impl"; +//// [package.json] +{ + "name": "typescript-fsa", + "version": "1.0.0" +} +//// [index.ts] +import * as _whatever from "p2"; +import { getA } from "typescript-fsa"; + +export const a = getA(); +//// [index.d.ts] +export const a: import("typescript-fsa").A; + + + +//// [index.js] +"use strict"; +exports.__esModule = true; +var typescript_fsa_1 = require("typescript-fsa"); +exports.a = typescript_fsa_1.getA(); + + +//// [index.d.ts] +export declare const a: import("typescript-fsa").A; diff --git a/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink.symbols b/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink.symbols new file mode 100644 index 00000000000..fa0a8593339 --- /dev/null +++ b/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink.symbols @@ -0,0 +1,43 @@ +=== /p1/node_modules/typescript-fsa/src/impl.d.ts === +export function getA(): A; +>getA : Symbol(getA, Decl(impl.d.ts, 0, 0)) +>A : Symbol(A, Decl(impl.d.ts, 0, 26)) + +export enum A { +>A : Symbol(A, Decl(impl.d.ts, 0, 26)) + + Val +>Val : Symbol(A.Val, Decl(impl.d.ts, 1, 15)) +} +=== /p1/node_modules/typescript-fsa/index.d.ts === +export * from "./src/impl"; +No type information for this code.=== /p2/node_modules/typescript-fsa/src/impl.d.ts === +export function getA(): A; +>getA : Symbol(getA, Decl(impl.d.ts, 0, 0)) +>A : Symbol(A, Decl(impl.d.ts, 0, 26)) + +export enum A { +>A : Symbol(A, Decl(impl.d.ts, 0, 26)) + + Val +>Val : Symbol(A.Val, Decl(impl.d.ts, 1, 15)) +} +=== /p2/node_modules/typescript-fsa/index.d.ts === +export * from "./src/impl"; +No type information for this code.=== /p1/index.ts === +import * as _whatever from "p2"; +>_whatever : Symbol(_whatever, Decl(index.ts, 0, 6)) + +import { getA } from "typescript-fsa"; +>getA : Symbol(getA, Decl(index.ts, 1, 8)) + +export const a = getA(); +>a : Symbol(a, Decl(index.ts, 3, 12)) +>getA : Symbol(getA, Decl(index.ts, 1, 8)) + +=== /p2/index.d.ts === +export const a: import("typescript-fsa").A; +>a : Symbol(a, Decl(index.d.ts, 0, 12)) +>A : Symbol(A, Decl(impl.d.ts, 0, 26)) + + diff --git a/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink.types b/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink.types new file mode 100644 index 00000000000..3f62193fd83 --- /dev/null +++ b/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink.types @@ -0,0 +1,41 @@ +=== /p1/node_modules/typescript-fsa/src/impl.d.ts === +export function getA(): A; +>getA : () => A + +export enum A { +>A : A + + Val +>Val : A +} +=== /p1/node_modules/typescript-fsa/index.d.ts === +export * from "./src/impl"; +No type information for this code.=== /p2/node_modules/typescript-fsa/src/impl.d.ts === +export function getA(): A; +>getA : () => A + +export enum A { +>A : A + + Val +>Val : A +} +=== /p2/node_modules/typescript-fsa/index.d.ts === +export * from "./src/impl"; +No type information for this code.=== /p1/index.ts === +import * as _whatever from "p2"; +>_whatever : typeof _whatever + +import { getA } from "typescript-fsa"; +>getA : () => import("/p1/node_modules/typescript-fsa/index").A + +export const a = getA(); +>a : import("/p1/node_modules/typescript-fsa/index").A +>getA() : import("/p1/node_modules/typescript-fsa/index").A +>getA : () => import("/p1/node_modules/typescript-fsa/index").A + +=== /p2/index.d.ts === +export const a: import("typescript-fsa").A; +>a : import("/p2/node_modules/typescript-fsa/index").A + + diff --git a/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink2.js b/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink2.js new file mode 100644 index 00000000000..22889aba461 --- /dev/null +++ b/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink2.js @@ -0,0 +1,33 @@ +//// [tests/cases/compiler/declarationEmitForGlobalishSpecifierSymlink2.ts] //// + +//// [impl.d.ts] +export function getA(): A; +export enum A { + Val +} +//// [index.d.ts] +export * from "./src/impl"; +//// [package.json] +{ + "name": "typescript-fsa", + "version": "1.0.0" +} +//// [index.ts] +import * as _whatever from "p2"; +import { getA } from "typescript-fsa"; + +export const a = getA(); +//// [index.d.ts] +export const a: import("typescript-fsa").A; + + + +//// [index.js] +"use strict"; +exports.__esModule = true; +var typescript_fsa_1 = require("typescript-fsa"); +exports.a = typescript_fsa_1.getA(); + + +//// [index.d.ts] +export declare const a: import("typescript-fsa").A; diff --git a/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink2.symbols b/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink2.symbols new file mode 100644 index 00000000000..e183f07d558 --- /dev/null +++ b/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink2.symbols @@ -0,0 +1,30 @@ +=== /cache/typescript-fsa/src/impl.d.ts === +export function getA(): A; +>getA : Symbol(getA, Decl(impl.d.ts, 0, 0)) +>A : Symbol(A, Decl(impl.d.ts, 0, 26)) + +export enum A { +>A : Symbol(A, Decl(impl.d.ts, 0, 26)) + + Val +>Val : Symbol(A.Val, Decl(impl.d.ts, 1, 15)) +} +=== /cache/typescript-fsa/index.d.ts === +export * from "./src/impl"; +No type information for this code.=== /p1/index.ts === +import * as _whatever from "p2"; +>_whatever : Symbol(_whatever, Decl(index.ts, 0, 6)) + +import { getA } from "typescript-fsa"; +>getA : Symbol(getA, Decl(index.ts, 1, 8)) + +export const a = getA(); +>a : Symbol(a, Decl(index.ts, 3, 12)) +>getA : Symbol(getA, Decl(index.ts, 1, 8)) + +=== /p2/index.d.ts === +export const a: import("typescript-fsa").A; +>a : Symbol(a, Decl(index.d.ts, 0, 12)) +>A : Symbol(A, Decl(impl.d.ts, 0, 26)) + + diff --git a/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink2.types b/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink2.types new file mode 100644 index 00000000000..7c214ced6b6 --- /dev/null +++ b/tests/baselines/reference/declarationEmitForGlobalishSpecifierSymlink2.types @@ -0,0 +1,29 @@ +=== /cache/typescript-fsa/src/impl.d.ts === +export function getA(): A; +>getA : () => A + +export enum A { +>A : A + + Val +>Val : A +} +=== /cache/typescript-fsa/index.d.ts === +export * from "./src/impl"; +No type information for this code.=== /p1/index.ts === +import * as _whatever from "p2"; +>_whatever : typeof _whatever + +import { getA } from "typescript-fsa"; +>getA : () => import("/cache/typescript-fsa/index").A + +export const a = getA(); +>a : import("/cache/typescript-fsa/index").A +>getA() : import("/cache/typescript-fsa/index").A +>getA : () => import("/cache/typescript-fsa/index").A + +=== /p2/index.d.ts === +export const a: import("typescript-fsa").A; +>a : import("/cache/typescript-fsa/index").A + + diff --git a/tests/baselines/reference/declarationEmitPrivateSymbolCausesVarDeclarationEmit2.js b/tests/baselines/reference/declarationEmitPrivateSymbolCausesVarDeclarationEmit2.js index ab986aba1e8..970590c136b 100644 --- a/tests/baselines/reference/declarationEmitPrivateSymbolCausesVarDeclarationEmit2.js +++ b/tests/baselines/reference/declarationEmitPrivateSymbolCausesVarDeclarationEmit2.js @@ -34,8 +34,8 @@ var C = /** @class */ (function () { } return C; }()); -_a = a_1.x; exports.C = C; +_a = a_1.x; //// [c.js] "use strict"; var __extends = (this && this.__extends) || (function () { @@ -64,8 +64,8 @@ var D = /** @class */ (function (_super) { } return D; }(b_1.C)); -_a = a_1.x; exports.D = D; +_a = a_1.x; //// [a.d.ts] diff --git a/tests/baselines/reference/decoratorsOnComputedProperties.js b/tests/baselines/reference/decoratorsOnComputedProperties.js index 2af6b460c05..3f0444b310a 100644 --- a/tests/baselines/reference/decoratorsOnComputedProperties.js +++ b/tests/baselines/reference/decoratorsOnComputedProperties.js @@ -196,7 +196,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; -var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21; +var _a, _b, _c, _d; +var _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21; function x(o, k) { } let i = 0; function foo() { return ++i + ""; } @@ -209,11 +210,11 @@ class A { this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_b] = null; - this[_d] = null; + this[_f] = null; + this[_h] = null; } } -foo(), _a = foo(), _b = foo(), _c = fieldNameB, _d = fieldNameC; +foo(), _e = foo(), _f = foo(), _g = fieldNameB, _h = fieldNameC; __decorate([ x ], A.prototype, "property", void 0); @@ -228,42 +229,42 @@ __decorate([ ], A.prototype, Symbol.iterator, void 0); __decorate([ x -], A.prototype, _a, void 0); +], A.prototype, _e, void 0); __decorate([ x -], A.prototype, _b, void 0); +], A.prototype, _f, void 0); __decorate([ x -], A.prototype, _c, void 0); +], A.prototype, _g, void 0); __decorate([ x -], A.prototype, _d, void 0); -void (_j = class B { +], A.prototype, _h, void 0); +void (_a = class B { constructor() { this["property2"] = 2; this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_f] = null; - this[_h] = null; + this[_k] = null; + this[_m] = null; } }, foo(), - _e = foo(), - _f = foo(), - _g = fieldNameB, - _h = fieldNameC, - _j); + _j = foo(), + _k = foo(), + _l = fieldNameB, + _m = fieldNameC, + _a); class C { constructor() { this["property2"] = 2; this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_l] = null; - this[_o] = null; + this[_p] = null; + this[_r] = null; } - [(foo(), _k = foo(), _l = foo(), _m = fieldNameB, _o = fieldNameC, "some" + "method")]() { } + [(foo(), _o = foo(), _p = foo(), _q = fieldNameB, _r = fieldNameC, "some" + "method")]() { } } __decorate([ x @@ -277,28 +278,28 @@ __decorate([ __decorate([ x ], C.prototype, Symbol.iterator, void 0); -__decorate([ - x -], C.prototype, _k, void 0); -__decorate([ - x -], C.prototype, _l, void 0); -__decorate([ - x -], C.prototype, _m, void 0); __decorate([ x ], C.prototype, _o, void 0); +__decorate([ + x +], C.prototype, _p, void 0); +__decorate([ + x +], C.prototype, _q, void 0); +__decorate([ + x +], C.prototype, _r, void 0); void class D { constructor() { this["property2"] = 2; this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_q] = null; - this[_s] = null; + this[_t] = null; + this[_v] = null; } - [(foo(), _p = foo(), _q = foo(), _r = fieldNameB, _s = fieldNameC, "some" + "method")]() { } + [(foo(), _s = foo(), _t = foo(), _u = fieldNameB, _v = fieldNameC, "some" + "method")]() { } }; class E { constructor() { @@ -306,12 +307,12 @@ class E { this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_u] = null; - this[_w] = null; + this[_x] = null; + this[_z] = null; } - [(foo(), _t = foo(), _u = foo(), "some" + "method")]() { } + [(foo(), _w = foo(), _x = foo(), "some" + "method")]() { } } -_v = fieldNameB, _w = fieldNameC; +_y = fieldNameB, _z = fieldNameC; __decorate([ x ], E.prototype, "property", void 0); @@ -324,45 +325,45 @@ __decorate([ __decorate([ x ], E.prototype, Symbol.iterator, void 0); -__decorate([ - x -], E.prototype, _t, void 0); -__decorate([ - x -], E.prototype, _u, void 0); -__decorate([ - x -], E.prototype, _v, void 0); __decorate([ x ], E.prototype, _w, void 0); -void (_1 = class F { +__decorate([ + x +], E.prototype, _x, void 0); +__decorate([ + x +], E.prototype, _y, void 0); +__decorate([ + x +], E.prototype, _z, void 0); +void (_b = class F { constructor() { this["property2"] = 2; this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_y] = null; - this[_0] = null; + this[_1] = null; + this[_3] = null; } - [(foo(), _x = foo(), _y = foo(), "some" + "method")]() { } + [(foo(), _0 = foo(), _1 = foo(), "some" + "method")]() { } }, - _z = fieldNameB, - _0 = fieldNameC, - _1); + _2 = fieldNameB, + _3 = fieldNameC, + _b); class G { constructor() { this["property2"] = 2; this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_3] = null; this[_5] = null; + this[_7] = null; } - [(foo(), _2 = foo(), _3 = foo(), "some" + "method")]() { } - [(_4 = fieldNameB, "some" + "method2")]() { } + [(foo(), _4 = foo(), _5 = foo(), "some" + "method")]() { } + [(_6 = fieldNameB, "some" + "method2")]() { } } -_5 = fieldNameC; +_7 = fieldNameC; __decorate([ x ], G.prototype, "property", void 0); @@ -375,45 +376,45 @@ __decorate([ __decorate([ x ], G.prototype, Symbol.iterator, void 0); -__decorate([ - x -], G.prototype, _2, void 0); -__decorate([ - x -], G.prototype, _3, void 0); __decorate([ x ], G.prototype, _4, void 0); __decorate([ x ], G.prototype, _5, void 0); -void (_10 = class H { +__decorate([ + x +], G.prototype, _6, void 0); +__decorate([ + x +], G.prototype, _7, void 0); +void (_c = class H { constructor() { this["property2"] = 2; this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_7] = null; this[_9] = null; + this[_11] = null; } - [(foo(), _6 = foo(), _7 = foo(), "some" + "method")]() { } - [(_8 = fieldNameB, "some" + "method2")]() { } + [(foo(), _8 = foo(), _9 = foo(), "some" + "method")]() { } + [(_10 = fieldNameB, "some" + "method2")]() { } }, - _9 = fieldNameC, - _10); + _11 = fieldNameC, + _c); class I { constructor() { this["property2"] = 2; this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_12] = null; - this[_15] = null; + this[_13] = null; + this[_16] = null; } - [(foo(), _11 = foo(), _12 = foo(), _13 = "some" + "method")]() { } - [(_14 = fieldNameB, "some" + "method2")]() { } + [(foo(), _12 = foo(), _13 = foo(), _14 = "some" + "method")]() { } + [(_15 = fieldNameB, "some" + "method2")]() { } } -_15 = fieldNameC; +_16 = fieldNameC; __decorate([ x ], I.prototype, "property", void 0); @@ -426,32 +427,32 @@ __decorate([ __decorate([ x ], I.prototype, Symbol.iterator, void 0); -__decorate([ - x -], I.prototype, _11, void 0); __decorate([ x ], I.prototype, _12, void 0); __decorate([ x -], I.prototype, _13, null); +], I.prototype, _13, void 0); __decorate([ x -], I.prototype, _14, void 0); +], I.prototype, _14, null); __decorate([ x ], I.prototype, _15, void 0); -void (_21 = class J { +__decorate([ + x +], I.prototype, _16, void 0); +void (_d = class J { constructor() { this["property2"] = 2; this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_17] = null; - this[_20] = null; + this[_18] = null; + this[_21] = null; } - [(foo(), _16 = foo(), _17 = foo(), _18 = "some" + "method")]() { } - [(_19 = fieldNameB, "some" + "method2")]() { } + [(foo(), _17 = foo(), _18 = foo(), _19 = "some" + "method")]() { } + [(_20 = fieldNameB, "some" + "method2")]() { } }, - _20 = fieldNameC, - _21); + _21 = fieldNameC, + _d); diff --git a/tests/baselines/reference/destructuringAssignmentWithDefault.js b/tests/baselines/reference/destructuringAssignmentWithDefault.js index df4addf0269..b2b0c31654b 100644 --- a/tests/baselines/reference/destructuringAssignmentWithDefault.js +++ b/tests/baselines/reference/destructuringAssignmentWithDefault.js @@ -2,6 +2,34 @@ const a: { x?: number } = { }; let x = 0; ({x = 1} = a); + +// Repro from #26235 + +function f1(options?: { color?: string, width?: number }) { + let { color, width } = options || {}; + ({ color, width } = options || {}); + let x1 = (options || {}).color; + let x2 = (options || {})["color"]; +} + +function f2(options?: [string?, number?]) { + let [str, num] = options || []; + [str, num] = options || []; + let x1 = (options || {})[0]; +} + +function f3(options?: { color: string, width: number }) { + let { color, width } = options || {}; + ({ color, width } = options || {}); + let x1 = (options || {}).color; + let x2 = (options || {})["color"]; +} + +function f4(options?: [string, number]) { + let [str, num] = options || []; + [str, num] = options || []; + let x1 = (options || {})[0]; +} //// [destructuringAssignmentWithDefault.js] @@ -9,3 +37,30 @@ var _a; var a = {}; var x = 0; (_a = a.x, x = _a === void 0 ? 1 : _a); +// Repro from #26235 +function f1(options) { + var _a; + var _b = options || {}, color = _b.color, width = _b.width; + (_a = options || {}, color = _a.color, width = _a.width); + var x1 = (options || {}).color; + var x2 = (options || {})["color"]; +} +function f2(options) { + var _a; + var _b = options || [], str = _b[0], num = _b[1]; + _a = options || [], str = _a[0], num = _a[1]; + var x1 = (options || {})[0]; +} +function f3(options) { + var _a; + var _b = options || {}, color = _b.color, width = _b.width; + (_a = options || {}, color = _a.color, width = _a.width); + var x1 = (options || {}).color; + var x2 = (options || {})["color"]; +} +function f4(options) { + var _a; + var _b = options || [], str = _b[0], num = _b[1]; + _a = options || [], str = _a[0], num = _a[1]; + var x1 = (options || {})[0]; +} diff --git a/tests/baselines/reference/destructuringAssignmentWithDefault.symbols b/tests/baselines/reference/destructuringAssignmentWithDefault.symbols index b011834c4f0..eef4bdcd97a 100644 --- a/tests/baselines/reference/destructuringAssignmentWithDefault.symbols +++ b/tests/baselines/reference/destructuringAssignmentWithDefault.symbols @@ -10,3 +10,101 @@ let x = 0; >x : Symbol(x, Decl(destructuringAssignmentWithDefault.ts, 2, 2)) >a : Symbol(a, Decl(destructuringAssignmentWithDefault.ts, 0, 5)) +// Repro from #26235 + +function f1(options?: { color?: string, width?: number }) { +>f1 : Symbol(f1, Decl(destructuringAssignmentWithDefault.ts, 2, 14)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 6, 12)) +>color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 6, 23)) +>width : Symbol(width, Decl(destructuringAssignmentWithDefault.ts, 6, 39)) + + let { color, width } = options || {}; +>color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 7, 9)) +>width : Symbol(width, Decl(destructuringAssignmentWithDefault.ts, 7, 16)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 6, 12)) + + ({ color, width } = options || {}); +>color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 8, 6)) +>width : Symbol(width, Decl(destructuringAssignmentWithDefault.ts, 8, 13)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 6, 12)) + + let x1 = (options || {}).color; +>x1 : Symbol(x1, Decl(destructuringAssignmentWithDefault.ts, 9, 7)) +>(options || {}).color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 6, 23)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 6, 12)) +>color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 6, 23)) + + let x2 = (options || {})["color"]; +>x2 : Symbol(x2, Decl(destructuringAssignmentWithDefault.ts, 10, 7)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 6, 12)) +>"color" : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 6, 23)) +} + +function f2(options?: [string?, number?]) { +>f2 : Symbol(f2, Decl(destructuringAssignmentWithDefault.ts, 11, 1)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 13, 12)) + + let [str, num] = options || []; +>str : Symbol(str, Decl(destructuringAssignmentWithDefault.ts, 14, 9)) +>num : Symbol(num, Decl(destructuringAssignmentWithDefault.ts, 14, 13)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 13, 12)) + + [str, num] = options || []; +>str : Symbol(str, Decl(destructuringAssignmentWithDefault.ts, 14, 9)) +>num : Symbol(num, Decl(destructuringAssignmentWithDefault.ts, 14, 13)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 13, 12)) + + let x1 = (options || {})[0]; +>x1 : Symbol(x1, Decl(destructuringAssignmentWithDefault.ts, 16, 7)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 13, 12)) +>0 : Symbol(0) +} + +function f3(options?: { color: string, width: number }) { +>f3 : Symbol(f3, Decl(destructuringAssignmentWithDefault.ts, 17, 1)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 19, 12)) +>color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 19, 23)) +>width : Symbol(width, Decl(destructuringAssignmentWithDefault.ts, 19, 38)) + + let { color, width } = options || {}; +>color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 20, 9)) +>width : Symbol(width, Decl(destructuringAssignmentWithDefault.ts, 20, 16)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 19, 12)) + + ({ color, width } = options || {}); +>color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 21, 6)) +>width : Symbol(width, Decl(destructuringAssignmentWithDefault.ts, 21, 13)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 19, 12)) + + let x1 = (options || {}).color; +>x1 : Symbol(x1, Decl(destructuringAssignmentWithDefault.ts, 22, 7)) +>(options || {}).color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 19, 23)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 19, 12)) +>color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 19, 23)) + + let x2 = (options || {})["color"]; +>x2 : Symbol(x2, Decl(destructuringAssignmentWithDefault.ts, 23, 7)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 19, 12)) +>"color" : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 19, 23)) +} + +function f4(options?: [string, number]) { +>f4 : Symbol(f4, Decl(destructuringAssignmentWithDefault.ts, 24, 1)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 26, 12)) + + let [str, num] = options || []; +>str : Symbol(str, Decl(destructuringAssignmentWithDefault.ts, 27, 9)) +>num : Symbol(num, Decl(destructuringAssignmentWithDefault.ts, 27, 13)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 26, 12)) + + [str, num] = options || []; +>str : Symbol(str, Decl(destructuringAssignmentWithDefault.ts, 27, 9)) +>num : Symbol(num, Decl(destructuringAssignmentWithDefault.ts, 27, 13)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 26, 12)) + + let x1 = (options || {})[0]; +>x1 : Symbol(x1, Decl(destructuringAssignmentWithDefault.ts, 29, 7)) +>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 26, 12)) +>0 : Symbol(0) +} + diff --git a/tests/baselines/reference/destructuringAssignmentWithDefault.types b/tests/baselines/reference/destructuringAssignmentWithDefault.types index 6347ccd0188..379bfe8b3bd 100644 --- a/tests/baselines/reference/destructuringAssignmentWithDefault.types +++ b/tests/baselines/reference/destructuringAssignmentWithDefault.types @@ -16,3 +16,149 @@ let x = 0; >1 : 1 >a : { x?: number | undefined; } +// Repro from #26235 + +function f1(options?: { color?: string, width?: number }) { +>f1 : (options?: { color?: string | undefined; width?: number | undefined; } | undefined) => void +>options : { color?: string | undefined; width?: number | undefined; } | undefined +>color : string | undefined +>width : number | undefined + + let { color, width } = options || {}; +>color : string | undefined +>width : number | undefined +>options || {} : { color?: string | undefined; width?: number | undefined; } +>options : { color?: string | undefined; width?: number | undefined; } | undefined +>{} : {} + + ({ color, width } = options || {}); +>({ color, width } = options || {}) : { color?: string | undefined; width?: number | undefined; } +>{ color, width } = options || {} : { color?: string | undefined; width?: number | undefined; } +>{ color, width } : { color: string | undefined; width: number | undefined; } +>color : string | undefined +>width : number | undefined +>options || {} : { color?: string | undefined; width?: number | undefined; } +>options : { color?: string | undefined; width?: number | undefined; } | undefined +>{} : {} + + let x1 = (options || {}).color; +>x1 : string | undefined +>(options || {}).color : string | undefined +>(options || {}) : { color?: string | undefined; width?: number | undefined; } +>options || {} : { color?: string | undefined; width?: number | undefined; } +>options : { color?: string | undefined; width?: number | undefined; } | undefined +>{} : {} +>color : string | undefined + + let x2 = (options || {})["color"]; +>x2 : string | undefined +>(options || {})["color"] : string | undefined +>(options || {}) : { color?: string | undefined; width?: number | undefined; } +>options || {} : { color?: string | undefined; width?: number | undefined; } +>options : { color?: string | undefined; width?: number | undefined; } | undefined +>{} : {} +>"color" : "color" +} + +function f2(options?: [string?, number?]) { +>f2 : (options?: [(string | undefined)?, (number | undefined)?] | undefined) => void +>options : [(string | undefined)?, (number | undefined)?] | undefined + + let [str, num] = options || []; +>str : string | undefined +>num : number | undefined +>options || [] : [(string | undefined)?, (number | undefined)?] +>options : [(string | undefined)?, (number | undefined)?] | undefined +>[] : [] + + [str, num] = options || []; +>[str, num] = options || [] : [(string | undefined)?, (number | undefined)?] +>[str, num] : [string | undefined, number | undefined] +>str : string | undefined +>num : number | undefined +>options || [] : [(string | undefined)?, (number | undefined)?] +>options : [(string | undefined)?, (number | undefined)?] | undefined +>[] : [] + + let x1 = (options || {})[0]; +>x1 : string | undefined +>(options || {})[0] : string | undefined +>(options || {}) : [(string | undefined)?, (number | undefined)?] | {} +>options || {} : [(string | undefined)?, (number | undefined)?] | {} +>options : [(string | undefined)?, (number | undefined)?] | undefined +>{} : {} +>0 : 0 +} + +function f3(options?: { color: string, width: number }) { +>f3 : (options?: { color: string; width: number; } | undefined) => void +>options : { color: string; width: number; } | undefined +>color : string +>width : number + + let { color, width } = options || {}; +>color : string | undefined +>width : number | undefined +>options || {} : { color: string; width: number; } | {} +>options : { color: string; width: number; } | undefined +>{} : {} + + ({ color, width } = options || {}); +>({ color, width } = options || {}) : { color: string; width: number; } | {} +>{ color, width } = options || {} : { color: string; width: number; } | {} +>{ color, width } : { color: string | undefined; width: number | undefined; } +>color : string | undefined +>width : number | undefined +>options || {} : { color: string; width: number; } | {} +>options : { color: string; width: number; } | undefined +>{} : {} + + let x1 = (options || {}).color; +>x1 : string | undefined +>(options || {}).color : string | undefined +>(options || {}) : { color: string; width: number; } | {} +>options || {} : { color: string; width: number; } | {} +>options : { color: string; width: number; } | undefined +>{} : {} +>color : string | undefined + + let x2 = (options || {})["color"]; +>x2 : string | undefined +>(options || {})["color"] : string | undefined +>(options || {}) : { color: string; width: number; } | {} +>options || {} : { color: string; width: number; } | {} +>options : { color: string; width: number; } | undefined +>{} : {} +>"color" : "color" +} + +function f4(options?: [string, number]) { +>f4 : (options?: [string, number] | undefined) => void +>options : [string, number] | undefined + + let [str, num] = options || []; +>str : string | undefined +>num : number | undefined +>options || [] : [] | [string, number] +>options : [string, number] | undefined +>[] : [] + + [str, num] = options || []; +>[str, num] = options || [] : [] | [string, number] +>[str, num] : [string | undefined, number | undefined] +>str : string | undefined +>num : number | undefined +>options || [] : [] | [string, number] +>options : [string, number] | undefined +>[] : [] + + let x1 = (options || {})[0]; +>x1 : string | undefined +>(options || {})[0] : string | undefined +>(options || {}) : [string, number] | {} +>options || {} : [string, number] | {} +>options : [string, number] | undefined +>{} : {} +>0 : 0 +} + diff --git a/tests/baselines/reference/fallbackToBindingPatternForTypeInference.symbols b/tests/baselines/reference/fallbackToBindingPatternForTypeInference.symbols index f57b234f39f..4f450e21c24 100644 --- a/tests/baselines/reference/fallbackToBindingPatternForTypeInference.symbols +++ b/tests/baselines/reference/fallbackToBindingPatternForTypeInference.symbols @@ -18,6 +18,7 @@ trans(([b,c]) => 'foo'); trans(({d: [e,f]}) => 'foo'); >trans : Symbol(trans, Decl(fallbackToBindingPatternForTypeInference.ts, 0, 0)) +>d : Symbol(d) >e : Symbol(e, Decl(fallbackToBindingPatternForTypeInference.ts, 3, 12)) >f : Symbol(f, Decl(fallbackToBindingPatternForTypeInference.ts, 3, 14)) diff --git a/tests/baselines/reference/globalThisUnknownNoImplicitAny.errors.txt b/tests/baselines/reference/globalThisUnknownNoImplicitAny.errors.txt index 0668d03f93b..907a6cd1ced 100644 --- a/tests/baselines/reference/globalThisUnknownNoImplicitAny.errors.txt +++ b/tests/baselines/reference/globalThisUnknownNoImplicitAny.errors.txt @@ -2,8 +2,10 @@ tests/cases/conformance/es2019/globalThisUnknownNoImplicitAny.ts(4,5): error TS2 tests/cases/conformance/es2019/globalThisUnknownNoImplicitAny.ts(5,6): error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature. tests/cases/conformance/es2019/globalThisUnknownNoImplicitAny.ts(6,12): error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature. tests/cases/conformance/es2019/globalThisUnknownNoImplicitAny.ts(8,5): error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'. -tests/cases/conformance/es2019/globalThisUnknownNoImplicitAny.ts(9,1): error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature. -tests/cases/conformance/es2019/globalThisUnknownNoImplicitAny.ts(10,1): error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature. +tests/cases/conformance/es2019/globalThisUnknownNoImplicitAny.ts(9,1): error TS7053: Element implicitly has an 'any' type because expression of type '"hi"' can't be used to index type 'typeof globalThis'. + Property 'hi' does not exist on type 'typeof globalThis'. +tests/cases/conformance/es2019/globalThisUnknownNoImplicitAny.ts(10,1): error TS7053: Element implicitly has an 'any' type because expression of type '"hi"' can't be used to index type 'typeof globalThis'. + Property 'hi' does not exist on type 'typeof globalThis'. ==== tests/cases/conformance/es2019/globalThisUnknownNoImplicitAny.ts (6 errors) ==== @@ -25,8 +27,10 @@ tests/cases/conformance/es2019/globalThisUnknownNoImplicitAny.ts(10,1): error TS !!! error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'. this['hi'] ~~~~~~~~~~ -!!! error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature. +!!! error TS7053: Element implicitly has an 'any' type because expression of type '"hi"' can't be used to index type 'typeof globalThis'. +!!! error TS7053: Property 'hi' does not exist on type 'typeof globalThis'. globalThis['hi'] ~~~~~~~~~~~~~~~~ -!!! error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature. +!!! error TS7053: Element implicitly has an 'any' type because expression of type '"hi"' can't be used to index type 'typeof globalThis'. +!!! error TS7053: Property 'hi' does not exist on type 'typeof globalThis'. \ No newline at end of file diff --git a/tests/baselines/reference/identicalTypesNoDifferByCheckOrder.js b/tests/baselines/reference/identicalTypesNoDifferByCheckOrder.js new file mode 100644 index 00000000000..a88b29ce254 --- /dev/null +++ b/tests/baselines/reference/identicalTypesNoDifferByCheckOrder.js @@ -0,0 +1,55 @@ +//// [identicalTypesNoDifferByCheckOrder.ts] +interface SomeProps { + x?: string; + y?: number; + renderAs?: FunctionComponent1 +} + +type SomePropsX = Required> & Omit; + +interface SomePropsClone { + x?: string; + y?: number; + renderAs?: FunctionComponent2 +} + +type SomePropsCloneX = Required> & Omit; + +type Validator = {(): boolean, opt?: T}; +type WeakValidationMap = {[K in keyof T]?: null extends T[K] ? Validator : Validator}; + +interface FunctionComponent1

{ + (props: P & { children?: unknown }): void; + propTypes?: WeakValidationMap

; +} + +interface FunctionComponent2

{ + (props: P & { children?: unknown }): void; + propTypes?: WeakValidationMap

; +} + +function needsComponentOfSomeProps3(...x: SomePropsClone[]): void {} +const comp3: FunctionComponent2 = null as any; +needsComponentOfSomeProps3({ renderAs: comp3 }); + +function needsComponentOfSomeProps2(...x: SomeProps[]): void {} +const comp2: FunctionComponent1 = null as any; +needsComponentOfSomeProps2({ renderAs: comp2 }); + +//// [identicalTypesNoDifferByCheckOrder.js] +function needsComponentOfSomeProps3() { + var x = []; + for (var _i = 0; _i < arguments.length; _i++) { + x[_i] = arguments[_i]; + } +} +var comp3 = null; +needsComponentOfSomeProps3({ renderAs: comp3 }); +function needsComponentOfSomeProps2() { + var x = []; + for (var _i = 0; _i < arguments.length; _i++) { + x[_i] = arguments[_i]; + } +} +var comp2 = null; +needsComponentOfSomeProps2({ renderAs: comp2 }); diff --git a/tests/baselines/reference/identicalTypesNoDifferByCheckOrder.symbols b/tests/baselines/reference/identicalTypesNoDifferByCheckOrder.symbols new file mode 100644 index 00000000000..6850276d340 --- /dev/null +++ b/tests/baselines/reference/identicalTypesNoDifferByCheckOrder.symbols @@ -0,0 +1,127 @@ +=== tests/cases/compiler/identicalTypesNoDifferByCheckOrder.ts === +interface SomeProps { +>SomeProps : Symbol(SomeProps, Decl(identicalTypesNoDifferByCheckOrder.ts, 0, 0)) + + x?: string; +>x : Symbol(SomeProps.x, Decl(identicalTypesNoDifferByCheckOrder.ts, 0, 21)) + + y?: number; +>y : Symbol(SomeProps.y, Decl(identicalTypesNoDifferByCheckOrder.ts, 1, 15)) + + renderAs?: FunctionComponent1 +>renderAs : Symbol(SomeProps.renderAs, Decl(identicalTypesNoDifferByCheckOrder.ts, 2, 15)) +>FunctionComponent1 : Symbol(FunctionComponent1, Decl(identicalTypesNoDifferByCheckOrder.ts, 17, 120)) +>SomeProps : Symbol(SomeProps, Decl(identicalTypesNoDifferByCheckOrder.ts, 0, 0)) +} + +type SomePropsX = Required> & Omit; +>SomePropsX : Symbol(SomePropsX, Decl(identicalTypesNoDifferByCheckOrder.ts, 4, 1)) +>Required : Symbol(Required, Decl(lib.es5.d.ts, --, --)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>SomeProps : Symbol(SomeProps, Decl(identicalTypesNoDifferByCheckOrder.ts, 0, 0)) +>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) +>SomeProps : Symbol(SomeProps, Decl(identicalTypesNoDifferByCheckOrder.ts, 0, 0)) + +interface SomePropsClone { +>SomePropsClone : Symbol(SomePropsClone, Decl(identicalTypesNoDifferByCheckOrder.ts, 6, 72)) + + x?: string; +>x : Symbol(SomePropsClone.x, Decl(identicalTypesNoDifferByCheckOrder.ts, 8, 26)) + + y?: number; +>y : Symbol(SomePropsClone.y, Decl(identicalTypesNoDifferByCheckOrder.ts, 9, 15)) + + renderAs?: FunctionComponent2 +>renderAs : Symbol(SomePropsClone.renderAs, Decl(identicalTypesNoDifferByCheckOrder.ts, 10, 15)) +>FunctionComponent2 : Symbol(FunctionComponent2, Decl(identicalTypesNoDifferByCheckOrder.ts, 22, 1)) +>SomeProps : Symbol(SomeProps, Decl(identicalTypesNoDifferByCheckOrder.ts, 0, 0)) +} + +type SomePropsCloneX = Required> & Omit; +>SomePropsCloneX : Symbol(SomePropsCloneX, Decl(identicalTypesNoDifferByCheckOrder.ts, 12, 1)) +>Required : Symbol(Required, Decl(lib.es5.d.ts, --, --)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>SomePropsClone : Symbol(SomePropsClone, Decl(identicalTypesNoDifferByCheckOrder.ts, 6, 72)) +>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) +>SomePropsClone : Symbol(SomePropsClone, Decl(identicalTypesNoDifferByCheckOrder.ts, 6, 72)) + +type Validator = {(): boolean, opt?: T}; +>Validator : Symbol(Validator, Decl(identicalTypesNoDifferByCheckOrder.ts, 14, 87)) +>T : Symbol(T, Decl(identicalTypesNoDifferByCheckOrder.ts, 16, 15)) +>opt : Symbol(opt, Decl(identicalTypesNoDifferByCheckOrder.ts, 16, 33)) +>T : Symbol(T, Decl(identicalTypesNoDifferByCheckOrder.ts, 16, 15)) + +type WeakValidationMap = {[K in keyof T]?: null extends T[K] ? Validator : Validator}; +>WeakValidationMap : Symbol(WeakValidationMap, Decl(identicalTypesNoDifferByCheckOrder.ts, 16, 43)) +>T : Symbol(T, Decl(identicalTypesNoDifferByCheckOrder.ts, 17, 23)) +>K : Symbol(K, Decl(identicalTypesNoDifferByCheckOrder.ts, 17, 30)) +>T : Symbol(T, Decl(identicalTypesNoDifferByCheckOrder.ts, 17, 23)) +>T : Symbol(T, Decl(identicalTypesNoDifferByCheckOrder.ts, 17, 23)) +>K : Symbol(K, Decl(identicalTypesNoDifferByCheckOrder.ts, 17, 30)) +>Validator : Symbol(Validator, Decl(identicalTypesNoDifferByCheckOrder.ts, 14, 87)) +>T : Symbol(T, Decl(identicalTypesNoDifferByCheckOrder.ts, 17, 23)) +>K : Symbol(K, Decl(identicalTypesNoDifferByCheckOrder.ts, 17, 30)) +>Validator : Symbol(Validator, Decl(identicalTypesNoDifferByCheckOrder.ts, 14, 87)) +>T : Symbol(T, Decl(identicalTypesNoDifferByCheckOrder.ts, 17, 23)) +>K : Symbol(K, Decl(identicalTypesNoDifferByCheckOrder.ts, 17, 30)) + +interface FunctionComponent1

{ +>FunctionComponent1 : Symbol(FunctionComponent1, Decl(identicalTypesNoDifferByCheckOrder.ts, 17, 120)) +>P : Symbol(P, Decl(identicalTypesNoDifferByCheckOrder.ts, 19, 29)) + + (props: P & { children?: unknown }): void; +>props : Symbol(props, Decl(identicalTypesNoDifferByCheckOrder.ts, 20, 5)) +>P : Symbol(P, Decl(identicalTypesNoDifferByCheckOrder.ts, 19, 29)) +>children : Symbol(children, Decl(identicalTypesNoDifferByCheckOrder.ts, 20, 17)) + + propTypes?: WeakValidationMap

; +>propTypes : Symbol(FunctionComponent1.propTypes, Decl(identicalTypesNoDifferByCheckOrder.ts, 20, 46)) +>WeakValidationMap : Symbol(WeakValidationMap, Decl(identicalTypesNoDifferByCheckOrder.ts, 16, 43)) +>P : Symbol(P, Decl(identicalTypesNoDifferByCheckOrder.ts, 19, 29)) +} + +interface FunctionComponent2

{ +>FunctionComponent2 : Symbol(FunctionComponent2, Decl(identicalTypesNoDifferByCheckOrder.ts, 22, 1)) +>P : Symbol(P, Decl(identicalTypesNoDifferByCheckOrder.ts, 24, 29)) + + (props: P & { children?: unknown }): void; +>props : Symbol(props, Decl(identicalTypesNoDifferByCheckOrder.ts, 25, 5)) +>P : Symbol(P, Decl(identicalTypesNoDifferByCheckOrder.ts, 24, 29)) +>children : Symbol(children, Decl(identicalTypesNoDifferByCheckOrder.ts, 25, 17)) + + propTypes?: WeakValidationMap

; +>propTypes : Symbol(FunctionComponent2.propTypes, Decl(identicalTypesNoDifferByCheckOrder.ts, 25, 46)) +>WeakValidationMap : Symbol(WeakValidationMap, Decl(identicalTypesNoDifferByCheckOrder.ts, 16, 43)) +>P : Symbol(P, Decl(identicalTypesNoDifferByCheckOrder.ts, 24, 29)) +} + +function needsComponentOfSomeProps3(...x: SomePropsClone[]): void {} +>needsComponentOfSomeProps3 : Symbol(needsComponentOfSomeProps3, Decl(identicalTypesNoDifferByCheckOrder.ts, 27, 1)) +>x : Symbol(x, Decl(identicalTypesNoDifferByCheckOrder.ts, 29, 36)) +>SomePropsClone : Symbol(SomePropsClone, Decl(identicalTypesNoDifferByCheckOrder.ts, 6, 72)) + +const comp3: FunctionComponent2 = null as any; +>comp3 : Symbol(comp3, Decl(identicalTypesNoDifferByCheckOrder.ts, 30, 5)) +>FunctionComponent2 : Symbol(FunctionComponent2, Decl(identicalTypesNoDifferByCheckOrder.ts, 22, 1)) +>SomePropsCloneX : Symbol(SomePropsCloneX, Decl(identicalTypesNoDifferByCheckOrder.ts, 12, 1)) + +needsComponentOfSomeProps3({ renderAs: comp3 }); +>needsComponentOfSomeProps3 : Symbol(needsComponentOfSomeProps3, Decl(identicalTypesNoDifferByCheckOrder.ts, 27, 1)) +>renderAs : Symbol(renderAs, Decl(identicalTypesNoDifferByCheckOrder.ts, 31, 28)) +>comp3 : Symbol(comp3, Decl(identicalTypesNoDifferByCheckOrder.ts, 30, 5)) + +function needsComponentOfSomeProps2(...x: SomeProps[]): void {} +>needsComponentOfSomeProps2 : Symbol(needsComponentOfSomeProps2, Decl(identicalTypesNoDifferByCheckOrder.ts, 31, 48)) +>x : Symbol(x, Decl(identicalTypesNoDifferByCheckOrder.ts, 33, 36)) +>SomeProps : Symbol(SomeProps, Decl(identicalTypesNoDifferByCheckOrder.ts, 0, 0)) + +const comp2: FunctionComponent1 = null as any; +>comp2 : Symbol(comp2, Decl(identicalTypesNoDifferByCheckOrder.ts, 34, 5)) +>FunctionComponent1 : Symbol(FunctionComponent1, Decl(identicalTypesNoDifferByCheckOrder.ts, 17, 120)) +>SomePropsX : Symbol(SomePropsX, Decl(identicalTypesNoDifferByCheckOrder.ts, 4, 1)) + +needsComponentOfSomeProps2({ renderAs: comp2 }); +>needsComponentOfSomeProps2 : Symbol(needsComponentOfSomeProps2, Decl(identicalTypesNoDifferByCheckOrder.ts, 31, 48)) +>renderAs : Symbol(renderAs, Decl(identicalTypesNoDifferByCheckOrder.ts, 35, 28)) +>comp2 : Symbol(comp2, Decl(identicalTypesNoDifferByCheckOrder.ts, 34, 5)) + diff --git a/tests/baselines/reference/identicalTypesNoDifferByCheckOrder.types b/tests/baselines/reference/identicalTypesNoDifferByCheckOrder.types new file mode 100644 index 00000000000..e4c691c6b95 --- /dev/null +++ b/tests/baselines/reference/identicalTypesNoDifferByCheckOrder.types @@ -0,0 +1,88 @@ +=== tests/cases/compiler/identicalTypesNoDifferByCheckOrder.ts === +interface SomeProps { + x?: string; +>x : string | undefined + + y?: number; +>y : number | undefined + + renderAs?: FunctionComponent1 +>renderAs : FunctionComponent1 | undefined +} + +type SomePropsX = Required> & Omit; +>SomePropsX : SomePropsX + +interface SomePropsClone { + x?: string; +>x : string | undefined + + y?: number; +>y : number | undefined + + renderAs?: FunctionComponent2 +>renderAs : FunctionComponent2 | undefined +} + +type SomePropsCloneX = Required> & Omit; +>SomePropsCloneX : SomePropsCloneX + +type Validator = {(): boolean, opt?: T}; +>Validator : Validator +>opt : T | undefined + +type WeakValidationMap = {[K in keyof T]?: null extends T[K] ? Validator : Validator}; +>WeakValidationMap : WeakValidationMap +>null : null +>null : null + +interface FunctionComponent1

{ + (props: P & { children?: unknown }): void; +>props : P & { children?: unknown; } +>children : unknown + + propTypes?: WeakValidationMap

; +>propTypes : WeakValidationMap

| undefined +} + +interface FunctionComponent2

{ + (props: P & { children?: unknown }): void; +>props : P & { children?: unknown; } +>children : unknown + + propTypes?: WeakValidationMap

; +>propTypes : WeakValidationMap

| undefined +} + +function needsComponentOfSomeProps3(...x: SomePropsClone[]): void {} +>needsComponentOfSomeProps3 : (...x: SomePropsClone[]) => void +>x : SomePropsClone[] + +const comp3: FunctionComponent2 = null as any; +>comp3 : FunctionComponent2 +>null as any : any +>null : null + +needsComponentOfSomeProps3({ renderAs: comp3 }); +>needsComponentOfSomeProps3({ renderAs: comp3 }) : void +>needsComponentOfSomeProps3 : (...x: SomePropsClone[]) => void +>{ renderAs: comp3 } : { renderAs: FunctionComponent2; } +>renderAs : FunctionComponent2 +>comp3 : FunctionComponent2 + +function needsComponentOfSomeProps2(...x: SomeProps[]): void {} +>needsComponentOfSomeProps2 : (...x: SomeProps[]) => void +>x : SomeProps[] + +const comp2: FunctionComponent1 = null as any; +>comp2 : FunctionComponent1 +>null as any : any +>null : null + +needsComponentOfSomeProps2({ renderAs: comp2 }); +>needsComponentOfSomeProps2({ renderAs: comp2 }) : void +>needsComponentOfSomeProps2 : (...x: SomeProps[]) => void +>{ renderAs: comp2 } : { renderAs: FunctionComponent1; } +>renderAs : FunctionComponent1 +>comp2 : FunctionComponent1 + diff --git a/tests/baselines/reference/implicitIndexSignatures.js b/tests/baselines/reference/implicitIndexSignatures.js index 6403f1f1543..a20c63979da 100644 --- a/tests/baselines/reference/implicitIndexSignatures.js +++ b/tests/baselines/reference/implicitIndexSignatures.js @@ -44,6 +44,18 @@ function f4() { const v3 = getNumberIndexValue(o1); const v4 = getNumberIndexValue(o2); } + +function f5() { + enum E1 { A, B } + enum E2 { A = "A", B = "B" } + enum E3 { A = 0, B = "B" } + const v1 = getStringIndexValue(E1); + const v2 = getStringIndexValue(E2); + const v3 = getStringIndexValue(E3); + const v4 = getNumberIndexValue(E1); + const v5 = getNumberIndexValue(E2); + const v6 = getNumberIndexValue(E3); +} //// [implicitIndexSignatures.js] @@ -83,3 +95,26 @@ function f4() { var v3 = getNumberIndexValue(o1); var v4 = getNumberIndexValue(o2); } +function f5() { + var E1; + (function (E1) { + E1[E1["A"] = 0] = "A"; + E1[E1["B"] = 1] = "B"; + })(E1 || (E1 = {})); + var E2; + (function (E2) { + E2["A"] = "A"; + E2["B"] = "B"; + })(E2 || (E2 = {})); + var E3; + (function (E3) { + E3[E3["A"] = 0] = "A"; + E3["B"] = "B"; + })(E3 || (E3 = {})); + var v1 = getStringIndexValue(E1); + var v2 = getStringIndexValue(E2); + var v3 = getStringIndexValue(E3); + var v4 = getNumberIndexValue(E1); + var v5 = getNumberIndexValue(E2); + var v6 = getNumberIndexValue(E3); +} diff --git a/tests/baselines/reference/implicitIndexSignatures.symbols b/tests/baselines/reference/implicitIndexSignatures.symbols index 1c8f06acc11..6f3e68f5058 100644 --- a/tests/baselines/reference/implicitIndexSignatures.symbols +++ b/tests/baselines/reference/implicitIndexSignatures.symbols @@ -168,3 +168,52 @@ function f4() { >o2 : Symbol(o2, Decl(implicitIndexSignatures.ts, 39, 7)) } +function f5() { +>f5 : Symbol(f5, Decl(implicitIndexSignatures.ts, 44, 1)) + + enum E1 { A, B } +>E1 : Symbol(E1, Decl(implicitIndexSignatures.ts, 46, 15)) +>A : Symbol(E1.A, Decl(implicitIndexSignatures.ts, 47, 13)) +>B : Symbol(E1.B, Decl(implicitIndexSignatures.ts, 47, 16)) + + enum E2 { A = "A", B = "B" } +>E2 : Symbol(E2, Decl(implicitIndexSignatures.ts, 47, 20)) +>A : Symbol(E2.A, Decl(implicitIndexSignatures.ts, 48, 13)) +>B : Symbol(E2.B, Decl(implicitIndexSignatures.ts, 48, 22)) + + enum E3 { A = 0, B = "B" } +>E3 : Symbol(E3, Decl(implicitIndexSignatures.ts, 48, 32)) +>A : Symbol(E3.A, Decl(implicitIndexSignatures.ts, 49, 13)) +>B : Symbol(E3.B, Decl(implicitIndexSignatures.ts, 49, 20)) + + const v1 = getStringIndexValue(E1); +>v1 : Symbol(v1, Decl(implicitIndexSignatures.ts, 50, 9)) +>getStringIndexValue : Symbol(getStringIndexValue, Decl(implicitIndexSignatures.ts, 11, 13)) +>E1 : Symbol(E1, Decl(implicitIndexSignatures.ts, 46, 15)) + + const v2 = getStringIndexValue(E2); +>v2 : Symbol(v2, Decl(implicitIndexSignatures.ts, 51, 9)) +>getStringIndexValue : Symbol(getStringIndexValue, Decl(implicitIndexSignatures.ts, 11, 13)) +>E2 : Symbol(E2, Decl(implicitIndexSignatures.ts, 47, 20)) + + const v3 = getStringIndexValue(E3); +>v3 : Symbol(v3, Decl(implicitIndexSignatures.ts, 52, 9)) +>getStringIndexValue : Symbol(getStringIndexValue, Decl(implicitIndexSignatures.ts, 11, 13)) +>E3 : Symbol(E3, Decl(implicitIndexSignatures.ts, 48, 32)) + + const v4 = getNumberIndexValue(E1); +>v4 : Symbol(v4, Decl(implicitIndexSignatures.ts, 53, 9)) +>getNumberIndexValue : Symbol(getNumberIndexValue, Decl(implicitIndexSignatures.ts, 13, 68)) +>E1 : Symbol(E1, Decl(implicitIndexSignatures.ts, 46, 15)) + + const v5 = getNumberIndexValue(E2); +>v5 : Symbol(v5, Decl(implicitIndexSignatures.ts, 54, 9)) +>getNumberIndexValue : Symbol(getNumberIndexValue, Decl(implicitIndexSignatures.ts, 13, 68)) +>E2 : Symbol(E2, Decl(implicitIndexSignatures.ts, 47, 20)) + + const v6 = getNumberIndexValue(E3); +>v6 : Symbol(v6, Decl(implicitIndexSignatures.ts, 55, 9)) +>getNumberIndexValue : Symbol(getNumberIndexValue, Decl(implicitIndexSignatures.ts, 13, 68)) +>E3 : Symbol(E3, Decl(implicitIndexSignatures.ts, 48, 32)) +} + diff --git a/tests/baselines/reference/implicitIndexSignatures.types b/tests/baselines/reference/implicitIndexSignatures.types index afad7bed570..c302edba32f 100644 --- a/tests/baselines/reference/implicitIndexSignatures.types +++ b/tests/baselines/reference/implicitIndexSignatures.types @@ -196,3 +196,62 @@ function f4() { >o2 : { 0: string; 1: string; count: number; } } +function f5() { +>f5 : () => void + + enum E1 { A, B } +>E1 : E1 +>A : E1.A +>B : E1.B + + enum E2 { A = "A", B = "B" } +>E2 : E2 +>A : E2.A +>"A" : "A" +>B : E2.B +>"B" : "B" + + enum E3 { A = 0, B = "B" } +>E3 : E3 +>A : E3.A +>0 : 0 +>B : E3.B +>"B" : "B" + + const v1 = getStringIndexValue(E1); +>v1 : string | E1 +>getStringIndexValue(E1) : string | E1 +>getStringIndexValue : (map: { [x: string]: T; }) => T +>E1 : typeof E1 + + const v2 = getStringIndexValue(E2); +>v2 : E2 +>getStringIndexValue(E2) : E2 +>getStringIndexValue : (map: { [x: string]: T; }) => T +>E2 : typeof E2 + + const v3 = getStringIndexValue(E3); +>v3 : string | E3.A +>getStringIndexValue(E3) : string | E3.A +>getStringIndexValue : (map: { [x: string]: T; }) => T +>E3 : typeof E3 + + const v4 = getNumberIndexValue(E1); +>v4 : string +>getNumberIndexValue(E1) : string +>getNumberIndexValue : (map: { [x: number]: T; }) => T +>E1 : typeof E1 + + const v5 = getNumberIndexValue(E2); +>v5 : unknown +>getNumberIndexValue(E2) : unknown +>getNumberIndexValue : (map: { [x: number]: T; }) => T +>E2 : typeof E2 + + const v6 = getNumberIndexValue(E3); +>v6 : string +>getNumberIndexValue(E3) : string +>getNumberIndexValue : (map: { [x: number]: T; }) => T +>E3 : typeof E3 +} + diff --git a/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.errors.txt b/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.errors.txt index 7c79c63f78a..aea21ac2504 100644 --- a/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.errors.txt +++ b/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.errors.txt @@ -200,4 +200,23 @@ tests/cases/compiler/inferFromGenericFunctionReturnTypes3.ts(180,26): error TS23 !!! error TS2322: Types of property 'state' are incompatible. !!! error TS2322: Type 'State.B' is not assignable to type 'State.A'. !!! related TS6502 tests/cases/compiler/inferFromGenericFunctionReturnTypes3.ts:179:28: The expected type comes from the return type of this signature. + + // Repros from #31443 + + enum Enum { A, B } + + class ClassWithConvert { + constructor(val: T) { } + convert(converter: { to: (v: T) => T; }) { } + } + + function fn(arg: ClassWithConvert, f: () => ClassWithConvert) { } + fn(new ClassWithConvert(Enum.A), () => new ClassWithConvert(Enum.A)); + + type Func = (x: T) => T; + + declare function makeFoo(x: T): Func; + declare function baz(x: Func, y: Func): void; + + baz(makeFoo(Enum.A), makeFoo(Enum.A)); \ No newline at end of file diff --git a/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.js b/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.js index 99070e6ddcb..b6a2e890b11 100644 --- a/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.js +++ b/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.js @@ -179,6 +179,25 @@ enum State { A, B } type Foo = { state: State } declare function bar(f: () => T[]): T[]; let x: Foo[] = bar(() => !!true ? [{ state: State.A }] : [{ state: State.B }]); // Error + +// Repros from #31443 + +enum Enum { A, B } + +class ClassWithConvert { + constructor(val: T) { } + convert(converter: { to: (v: T) => T; }) { } +} + +function fn(arg: ClassWithConvert, f: () => ClassWithConvert) { } +fn(new ClassWithConvert(Enum.A), () => new ClassWithConvert(Enum.A)); + +type Func = (x: T) => T; + +declare function makeFoo(x: T): Func; +declare function baz(x: Func, y: Func): void; + +baz(makeFoo(Enum.A), makeFoo(Enum.A)); //// [inferFromGenericFunctionReturnTypes3.js] @@ -278,6 +297,19 @@ var State; State[State["B"] = 1] = "B"; })(State || (State = {})); let x = bar(() => !!true ? [{ state: State.A }] : [{ state: State.B }]); // Error +// Repros from #31443 +var Enum; +(function (Enum) { + Enum[Enum["A"] = 0] = "A"; + Enum[Enum["B"] = 1] = "B"; +})(Enum || (Enum = {})); +class ClassWithConvert { + constructor(val) { } + convert(converter) { } +} +function fn(arg, f) { } +fn(new ClassWithConvert(Enum.A), () => new ClassWithConvert(Enum.A)); +baz(makeFoo(Enum.A), makeFoo(Enum.A)); //// [inferFromGenericFunctionReturnTypes3.d.ts] diff --git a/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.symbols b/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.symbols index f89421cde07..ecf867a2bf7 100644 --- a/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.symbols +++ b/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.symbols @@ -459,3 +459,84 @@ let x: Foo[] = bar(() => !!true ? [{ state: State.A }] : [{ state: State.B }]); >State : Symbol(State, Decl(inferFromGenericFunctionReturnTypes3.ts, 174, 56)) >B : Symbol(State.B, Decl(inferFromGenericFunctionReturnTypes3.ts, 176, 15)) +// Repros from #31443 + +enum Enum { A, B } +>Enum : Symbol(Enum, Decl(inferFromGenericFunctionReturnTypes3.ts, 179, 79)) +>A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11)) +>B : Symbol(Enum.B, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 14)) + +class ClassWithConvert { +>ClassWithConvert : Symbol(ClassWithConvert, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 18)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 185, 23)) + + constructor(val: T) { } +>val : Symbol(val, Decl(inferFromGenericFunctionReturnTypes3.ts, 186, 14)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 185, 23)) + + convert(converter: { to: (v: T) => T; }) { } +>convert : Symbol(ClassWithConvert.convert, Decl(inferFromGenericFunctionReturnTypes3.ts, 186, 25)) +>converter : Symbol(converter, Decl(inferFromGenericFunctionReturnTypes3.ts, 187, 10)) +>to : Symbol(to, Decl(inferFromGenericFunctionReturnTypes3.ts, 187, 22)) +>v : Symbol(v, Decl(inferFromGenericFunctionReturnTypes3.ts, 187, 28)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 185, 23)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 185, 23)) +} + +function fn(arg: ClassWithConvert, f: () => ClassWithConvert) { } +>fn : Symbol(fn, Decl(inferFromGenericFunctionReturnTypes3.ts, 188, 1)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 190, 12)) +>arg : Symbol(arg, Decl(inferFromGenericFunctionReturnTypes3.ts, 190, 15)) +>ClassWithConvert : Symbol(ClassWithConvert, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 18)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 190, 12)) +>f : Symbol(f, Decl(inferFromGenericFunctionReturnTypes3.ts, 190, 40)) +>ClassWithConvert : Symbol(ClassWithConvert, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 18)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 190, 12)) + +fn(new ClassWithConvert(Enum.A), () => new ClassWithConvert(Enum.A)); +>fn : Symbol(fn, Decl(inferFromGenericFunctionReturnTypes3.ts, 188, 1)) +>ClassWithConvert : Symbol(ClassWithConvert, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 18)) +>Enum.A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11)) +>Enum : Symbol(Enum, Decl(inferFromGenericFunctionReturnTypes3.ts, 179, 79)) +>A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11)) +>ClassWithConvert : Symbol(ClassWithConvert, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 18)) +>Enum.A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11)) +>Enum : Symbol(Enum, Decl(inferFromGenericFunctionReturnTypes3.ts, 179, 79)) +>A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11)) + +type Func = (x: T) => T; +>Func : Symbol(Func, Decl(inferFromGenericFunctionReturnTypes3.ts, 191, 69)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 193, 10)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes3.ts, 193, 16)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 193, 10)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 193, 10)) + +declare function makeFoo(x: T): Func; +>makeFoo : Symbol(makeFoo, Decl(inferFromGenericFunctionReturnTypes3.ts, 193, 27)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 195, 25)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes3.ts, 195, 28)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 195, 25)) +>Func : Symbol(Func, Decl(inferFromGenericFunctionReturnTypes3.ts, 191, 69)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 195, 25)) + +declare function baz(x: Func, y: Func): void; +>baz : Symbol(baz, Decl(inferFromGenericFunctionReturnTypes3.ts, 195, 43)) +>U : Symbol(U, Decl(inferFromGenericFunctionReturnTypes3.ts, 196, 21)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes3.ts, 196, 24)) +>Func : Symbol(Func, Decl(inferFromGenericFunctionReturnTypes3.ts, 191, 69)) +>U : Symbol(U, Decl(inferFromGenericFunctionReturnTypes3.ts, 196, 21)) +>y : Symbol(y, Decl(inferFromGenericFunctionReturnTypes3.ts, 196, 35)) +>Func : Symbol(Func, Decl(inferFromGenericFunctionReturnTypes3.ts, 191, 69)) +>U : Symbol(U, Decl(inferFromGenericFunctionReturnTypes3.ts, 196, 21)) + +baz(makeFoo(Enum.A), makeFoo(Enum.A)); +>baz : Symbol(baz, Decl(inferFromGenericFunctionReturnTypes3.ts, 195, 43)) +>makeFoo : Symbol(makeFoo, Decl(inferFromGenericFunctionReturnTypes3.ts, 193, 27)) +>Enum.A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11)) +>Enum : Symbol(Enum, Decl(inferFromGenericFunctionReturnTypes3.ts, 179, 79)) +>A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11)) +>makeFoo : Symbol(makeFoo, Decl(inferFromGenericFunctionReturnTypes3.ts, 193, 27)) +>Enum.A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11)) +>Enum : Symbol(Enum, Decl(inferFromGenericFunctionReturnTypes3.ts, 179, 79)) +>A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11)) + diff --git a/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.types b/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.types index fd83694a171..4c56070fd3c 100644 --- a/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.types +++ b/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.types @@ -506,3 +506,70 @@ let x: Foo[] = bar(() => !!true ? [{ state: State.A }] : [{ state: State.B }]); >State : typeof State >B : State.B +// Repros from #31443 + +enum Enum { A, B } +>Enum : Enum +>A : Enum.A +>B : Enum.B + +class ClassWithConvert { +>ClassWithConvert : ClassWithConvert + + constructor(val: T) { } +>val : T + + convert(converter: { to: (v: T) => T; }) { } +>convert : (converter: { to: (v: T) => T; }) => void +>converter : { to: (v: T) => T; } +>to : (v: T) => T +>v : T +} + +function fn(arg: ClassWithConvert, f: () => ClassWithConvert) { } +>fn : (arg: ClassWithConvert, f: () => ClassWithConvert) => void +>arg : ClassWithConvert +>f : () => ClassWithConvert + +fn(new ClassWithConvert(Enum.A), () => new ClassWithConvert(Enum.A)); +>fn(new ClassWithConvert(Enum.A), () => new ClassWithConvert(Enum.A)) : void +>fn : (arg: ClassWithConvert, f: () => ClassWithConvert) => void +>new ClassWithConvert(Enum.A) : ClassWithConvert +>ClassWithConvert : typeof ClassWithConvert +>Enum.A : Enum.A +>Enum : typeof Enum +>A : Enum.A +>() => new ClassWithConvert(Enum.A) : () => ClassWithConvert +>new ClassWithConvert(Enum.A) : ClassWithConvert +>ClassWithConvert : typeof ClassWithConvert +>Enum.A : Enum.A +>Enum : typeof Enum +>A : Enum.A + +type Func = (x: T) => T; +>Func : Func +>x : T + +declare function makeFoo(x: T): Func; +>makeFoo : (x: T) => Func +>x : T + +declare function baz(x: Func, y: Func): void; +>baz : (x: Func, y: Func) => void +>x : Func +>y : Func + +baz(makeFoo(Enum.A), makeFoo(Enum.A)); +>baz(makeFoo(Enum.A), makeFoo(Enum.A)) : void +>baz : (x: Func, y: Func) => void +>makeFoo(Enum.A) : Func +>makeFoo : (x: T) => Func +>Enum.A : Enum.A +>Enum : typeof Enum +>A : Enum.A +>makeFoo(Enum.A) : Func +>makeFoo : (x: T) => Func +>Enum.A : Enum.A +>Enum : typeof Enum +>A : Enum.A + diff --git a/tests/baselines/reference/inferenceDoesntCompareAgainstUninstantiatedTypeParameter.js b/tests/baselines/reference/inferenceDoesntCompareAgainstUninstantiatedTypeParameter.js new file mode 100644 index 00000000000..c3dd7d42112 --- /dev/null +++ b/tests/baselines/reference/inferenceDoesntCompareAgainstUninstantiatedTypeParameter.js @@ -0,0 +1,67 @@ +//// [inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts] +class ClassA { + constructor(private entity?: TEntityClass, public settings?: SettingsInterface) { + + } +} +export interface ValueInterface { + func?: (row: TValueClass) => any; + value?: string; +} +export interface SettingsInterface { + values?: (row: TClass) => ValueInterface[], +} +class ConcreteClass { + theName = 'myClass'; +} + +var thisGetsTheFalseError = new ClassA(new ConcreteClass(), { + values: o => [ + { + value: o.theName, + func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' + } + ] +}); + +var thisIsOk = new ClassA(new ConcreteClass(), { + values: o => [ + { + value: o.theName, + func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' + } + ] +}); + +//// [inferenceDoesntCompareAgainstUninstantiatedTypeParameter.js] +"use strict"; +exports.__esModule = true; +var ClassA = /** @class */ (function () { + function ClassA(entity, settings) { + this.entity = entity; + this.settings = settings; + } + return ClassA; +}()); +var ConcreteClass = /** @class */ (function () { + function ConcreteClass() { + this.theName = 'myClass'; + } + return ConcreteClass; +}()); +var thisGetsTheFalseError = new ClassA(new ConcreteClass(), { + values: function (o) { return [ + { + value: o.theName, + func: function (x) { return 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj'; } + } + ]; } +}); +var thisIsOk = new ClassA(new ConcreteClass(), { + values: function (o) { return [ + { + value: o.theName, + func: function (x) { return 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj'; } + } + ]; } +}); diff --git a/tests/baselines/reference/inferenceDoesntCompareAgainstUninstantiatedTypeParameter.symbols b/tests/baselines/reference/inferenceDoesntCompareAgainstUninstantiatedTypeParameter.symbols new file mode 100644 index 00000000000..a47f3db5b55 --- /dev/null +++ b/tests/baselines/reference/inferenceDoesntCompareAgainstUninstantiatedTypeParameter.symbols @@ -0,0 +1,88 @@ +=== tests/cases/compiler/inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts === +class ClassA { +>ClassA : Symbol(ClassA, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 0, 0)) +>TEntityClass : Symbol(TEntityClass, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 0, 13)) + + constructor(private entity?: TEntityClass, public settings?: SettingsInterface) { +>entity : Symbol(ClassA.entity, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 1, 16)) +>TEntityClass : Symbol(TEntityClass, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 0, 13)) +>settings : Symbol(ClassA.settings, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 1, 46)) +>SettingsInterface : Symbol(SettingsInterface, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 8, 1)) +>TEntityClass : Symbol(TEntityClass, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 0, 13)) + + } +} +export interface ValueInterface { +>ValueInterface : Symbol(ValueInterface, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 4, 1)) +>TValueClass : Symbol(TValueClass, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 5, 32)) + + func?: (row: TValueClass) => any; +>func : Symbol(ValueInterface.func, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 5, 46)) +>row : Symbol(row, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 6, 12)) +>TValueClass : Symbol(TValueClass, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 5, 32)) + + value?: string; +>value : Symbol(ValueInterface.value, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 6, 37)) +} +export interface SettingsInterface { +>SettingsInterface : Symbol(SettingsInterface, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 8, 1)) +>TClass : Symbol(TClass, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 9, 35)) + + values?: (row: TClass) => ValueInterface[], +>values : Symbol(SettingsInterface.values, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 9, 44)) +>row : Symbol(row, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 10, 14)) +>TClass : Symbol(TClass, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 9, 35)) +>ValueInterface : Symbol(ValueInterface, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 4, 1)) +>TClass : Symbol(TClass, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 9, 35)) +} +class ConcreteClass { +>ConcreteClass : Symbol(ConcreteClass, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 11, 1)) + + theName = 'myClass'; +>theName : Symbol(ConcreteClass.theName, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 12, 21)) +} + +var thisGetsTheFalseError = new ClassA(new ConcreteClass(), { +>thisGetsTheFalseError : Symbol(thisGetsTheFalseError, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 16, 3)) +>ClassA : Symbol(ClassA, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 0, 0)) +>ConcreteClass : Symbol(ConcreteClass, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 11, 1)) + + values: o => [ +>values : Symbol(values, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 16, 61)) +>o : Symbol(o, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 17, 11)) + { + value: o.theName, +>value : Symbol(value, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 18, 9)) +>o.theName : Symbol(ConcreteClass.theName, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 12, 21)) +>o : Symbol(o, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 17, 11)) +>theName : Symbol(ConcreteClass.theName, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 12, 21)) + + func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' +>func : Symbol(func, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 19, 29)) +>x : Symbol(x, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 20, 17)) + } + ] +}); + +var thisIsOk = new ClassA(new ConcreteClass(), { +>thisIsOk : Symbol(thisIsOk, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 25, 3)) +>ClassA : Symbol(ClassA, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 0, 0)) +>ConcreteClass : Symbol(ConcreteClass, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 11, 1)) +>ConcreteClass : Symbol(ConcreteClass, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 11, 1)) + + values: o => [ +>values : Symbol(values, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 25, 63)) +>o : Symbol(o, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 26, 11)) + { + value: o.theName, +>value : Symbol(value, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 27, 9)) +>o.theName : Symbol(ConcreteClass.theName, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 12, 21)) +>o : Symbol(o, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 26, 11)) +>theName : Symbol(ConcreteClass.theName, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 12, 21)) + + func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' +>func : Symbol(func, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 28, 29)) +>x : Symbol(x, Decl(inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts, 29, 17)) + } + ] +}); diff --git a/tests/baselines/reference/inferenceDoesntCompareAgainstUninstantiatedTypeParameter.types b/tests/baselines/reference/inferenceDoesntCompareAgainstUninstantiatedTypeParameter.types new file mode 100644 index 00000000000..bda9aae9a4e --- /dev/null +++ b/tests/baselines/reference/inferenceDoesntCompareAgainstUninstantiatedTypeParameter.types @@ -0,0 +1,92 @@ +=== tests/cases/compiler/inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts === +class ClassA { +>ClassA : ClassA + + constructor(private entity?: TEntityClass, public settings?: SettingsInterface) { +>entity : TEntityClass +>settings : SettingsInterface + + } +} +export interface ValueInterface { + func?: (row: TValueClass) => any; +>func : (row: TValueClass) => any +>row : TValueClass + + value?: string; +>value : string +} +export interface SettingsInterface { + values?: (row: TClass) => ValueInterface[], +>values : (row: TClass) => ValueInterface[] +>row : TClass +} +class ConcreteClass { +>ConcreteClass : ConcreteClass + + theName = 'myClass'; +>theName : string +>'myClass' : "myClass" +} + +var thisGetsTheFalseError = new ClassA(new ConcreteClass(), { +>thisGetsTheFalseError : ClassA +>new ClassA(new ConcreteClass(), { values: o => [ { value: o.theName, func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' } ]}) : ClassA +>ClassA : typeof ClassA +>new ConcreteClass() : ConcreteClass +>ConcreteClass : typeof ConcreteClass +>{ values: o => [ { value: o.theName, func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' } ]} : { values: (o: ConcreteClass) => { value: string; func: (x: ConcreteClass) => string; }[]; } + + values: o => [ +>values : (o: ConcreteClass) => { value: string; func: (x: ConcreteClass) => string; }[] +>o => [ { value: o.theName, func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' } ] : (o: ConcreteClass) => { value: string; func: (x: ConcreteClass) => string; }[] +>o : ConcreteClass +>[ { value: o.theName, func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' } ] : { value: string; func: (x: ConcreteClass) => string; }[] + { +>{ value: o.theName, func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' } : { value: string; func: (x: ConcreteClass) => string; } + + value: o.theName, +>value : string +>o.theName : string +>o : ConcreteClass +>theName : string + + func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' +>func : (x: ConcreteClass) => string +>x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' : (x: ConcreteClass) => string +>x : ConcreteClass +>'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' : "asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj" + } + ] +}); + +var thisIsOk = new ClassA(new ConcreteClass(), { +>thisIsOk : ClassA +>new ClassA(new ConcreteClass(), { values: o => [ { value: o.theName, func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' } ]}) : ClassA +>ClassA : typeof ClassA +>new ConcreteClass() : ConcreteClass +>ConcreteClass : typeof ConcreteClass +>{ values: o => [ { value: o.theName, func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' } ]} : { values: (o: ConcreteClass) => { value: string; func: (x: ConcreteClass) => string; }[]; } + + values: o => [ +>values : (o: ConcreteClass) => { value: string; func: (x: ConcreteClass) => string; }[] +>o => [ { value: o.theName, func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' } ] : (o: ConcreteClass) => { value: string; func: (x: ConcreteClass) => string; }[] +>o : ConcreteClass +>[ { value: o.theName, func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' } ] : { value: string; func: (x: ConcreteClass) => string; }[] + { +>{ value: o.theName, func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' } : { value: string; func: (x: ConcreteClass) => string; } + + value: o.theName, +>value : string +>o.theName : string +>o : ConcreteClass +>theName : string + + func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' +>func : (x: ConcreteClass) => string +>x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' : (x: ConcreteClass) => string +>x : ConcreteClass +>'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' : "asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj" + } + ] +}); diff --git a/tests/baselines/reference/initializedDestructuringAssignmentTypes.types b/tests/baselines/reference/initializedDestructuringAssignmentTypes.types index bb30a395cff..333fc5d92cc 100644 --- a/tests/baselines/reference/initializedDestructuringAssignmentTypes.types +++ b/tests/baselines/reference/initializedDestructuringAssignmentTypes.types @@ -9,7 +9,7 @@ const [, a = ''] = ''.match('') || []; >'' : "" >match : (regexp: string | RegExp) => RegExpMatchArray >'' : "" ->[] : [undefined?, ""?] +>[] : undefined[] a.toFixed() >a.toFixed() : any diff --git a/tests/baselines/reference/intersectionTypeMembers.js b/tests/baselines/reference/intersectionTypeMembers.js index 59968b007db..867a6f0fc66 100644 --- a/tests/baselines/reference/intersectionTypeMembers.js +++ b/tests/baselines/reference/intersectionTypeMembers.js @@ -43,6 +43,28 @@ const de: D & E = { other: { g: 101 } } } + +// Additional test case with >2 doubly nested members so fix for #31441 is tested w/ excess props +interface F { + nested: { doublyNested: { g: string; } } +} + +interface G { + nested: { doublyNested: { h: string; } } +} + +const defg: D & E & F & G = { + nested: { + doublyNested: { + d: 'yes', + f: 'no', + g: 'ok', + h: 'affirmative' + }, + different: { e: 12 }, + other: { g: 101 } + } +} //// [intersectionTypeMembers.js] @@ -69,3 +91,15 @@ var de = { other: { g: 101 } } }; +var defg = { + nested: { + doublyNested: { + d: 'yes', + f: 'no', + g: 'ok', + h: 'affirmative' + }, + different: { e: 12 }, + other: { g: 101 } + } +}; diff --git a/tests/baselines/reference/intersectionTypeMembers.symbols b/tests/baselines/reference/intersectionTypeMembers.symbols index be47b2960db..b4629d1659d 100644 --- a/tests/baselines/reference/intersectionTypeMembers.symbols +++ b/tests/baselines/reference/intersectionTypeMembers.symbols @@ -146,3 +146,58 @@ const de: D & E = { } } +// Additional test case with >2 doubly nested members so fix for #31441 is tested w/ excess props +interface F { +>F : Symbol(F, Decl(intersectionTypeMembers.ts, 43, 1)) + + nested: { doublyNested: { g: string; } } +>nested : Symbol(F.nested, Decl(intersectionTypeMembers.ts, 46, 13)) +>doublyNested : Symbol(doublyNested, Decl(intersectionTypeMembers.ts, 47, 13)) +>g : Symbol(g, Decl(intersectionTypeMembers.ts, 47, 29)) +} + +interface G { +>G : Symbol(G, Decl(intersectionTypeMembers.ts, 48, 1)) + + nested: { doublyNested: { h: string; } } +>nested : Symbol(G.nested, Decl(intersectionTypeMembers.ts, 50, 13)) +>doublyNested : Symbol(doublyNested, Decl(intersectionTypeMembers.ts, 51, 13)) +>h : Symbol(h, Decl(intersectionTypeMembers.ts, 51, 29)) +} + +const defg: D & E & F & G = { +>defg : Symbol(defg, Decl(intersectionTypeMembers.ts, 54, 5)) +>D : Symbol(D, Decl(intersectionTypeMembers.ts, 26, 14)) +>E : Symbol(E, Decl(intersectionTypeMembers.ts, 30, 1)) +>F : Symbol(F, Decl(intersectionTypeMembers.ts, 43, 1)) +>G : Symbol(G, Decl(intersectionTypeMembers.ts, 48, 1)) + + nested: { +>nested : Symbol(nested, Decl(intersectionTypeMembers.ts, 54, 29)) + + doublyNested: { +>doublyNested : Symbol(doublyNested, Decl(intersectionTypeMembers.ts, 55, 13)) + + d: 'yes', +>d : Symbol(d, Decl(intersectionTypeMembers.ts, 56, 23)) + + f: 'no', +>f : Symbol(f, Decl(intersectionTypeMembers.ts, 57, 21)) + + g: 'ok', +>g : Symbol(g, Decl(intersectionTypeMembers.ts, 58, 20)) + + h: 'affirmative' +>h : Symbol(h, Decl(intersectionTypeMembers.ts, 59, 20)) + + }, + different: { e: 12 }, +>different : Symbol(different, Decl(intersectionTypeMembers.ts, 61, 10)) +>e : Symbol(e, Decl(intersectionTypeMembers.ts, 62, 20)) + + other: { g: 101 } +>other : Symbol(other, Decl(intersectionTypeMembers.ts, 62, 29)) +>g : Symbol(g, Decl(intersectionTypeMembers.ts, 63, 16)) + } +} + diff --git a/tests/baselines/reference/intersectionTypeMembers.types b/tests/baselines/reference/intersectionTypeMembers.types index eb9d5fa4eb8..817fa044624 100644 --- a/tests/baselines/reference/intersectionTypeMembers.types +++ b/tests/baselines/reference/intersectionTypeMembers.types @@ -148,3 +148,61 @@ const de: D & E = { } } +// Additional test case with >2 doubly nested members so fix for #31441 is tested w/ excess props +interface F { + nested: { doublyNested: { g: string; } } +>nested : { doublyNested: { g: string; }; } +>doublyNested : { g: string; } +>g : string +} + +interface G { + nested: { doublyNested: { h: string; } } +>nested : { doublyNested: { h: string; }; } +>doublyNested : { h: string; } +>h : string +} + +const defg: D & E & F & G = { +>defg : D & E & F & G +>{ nested: { doublyNested: { d: 'yes', f: 'no', g: 'ok', h: 'affirmative' }, different: { e: 12 }, other: { g: 101 } }} : { nested: { doublyNested: { d: string; f: string; g: string; h: string; }; different: { e: number; }; other: { g: number; }; }; } + + nested: { +>nested : { doublyNested: { d: string; f: string; g: string; h: string; }; different: { e: number; }; other: { g: number; }; } +>{ doublyNested: { d: 'yes', f: 'no', g: 'ok', h: 'affirmative' }, different: { e: 12 }, other: { g: 101 } } : { doublyNested: { d: string; f: string; g: string; h: string; }; different: { e: number; }; other: { g: number; }; } + + doublyNested: { +>doublyNested : { d: string; f: string; g: string; h: string; } +>{ d: 'yes', f: 'no', g: 'ok', h: 'affirmative' } : { d: string; f: string; g: string; h: string; } + + d: 'yes', +>d : string +>'yes' : "yes" + + f: 'no', +>f : string +>'no' : "no" + + g: 'ok', +>g : string +>'ok' : "ok" + + h: 'affirmative' +>h : string +>'affirmative' : "affirmative" + + }, + different: { e: 12 }, +>different : { e: number; } +>{ e: 12 } : { e: number; } +>e : number +>12 : 12 + + other: { g: 101 } +>other : { g: number; } +>{ g: 101 } : { g: number; } +>g : number +>101 : 101 + } +} + diff --git a/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt b/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt index 1cad297c52d..fffeac41ff7 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt +++ b/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt @@ -15,7 +15,8 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(26,7): error TS233 tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(27,5): error TS2322: Type '1' is not assignable to type 'T[keyof T]'. tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(31,5): error TS2322: Type '{ [key: string]: number; }' is not assignable to type '{ [P in K]: number; }'. tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(38,5): error TS2322: Type '{ [x: string]: number; }' is not assignable to type '{ [P in K]: number; }'. -tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(50,3): error TS7017: Element implicitly has an 'any' type because type 'Item' has no index signature. +tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(50,3): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Item'. + No index signature with a parameter of type 'string' was found on type 'Item'. tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(51,3): error TS2322: Type '123' is not assignable to type 'string & number'. Type '123' is not assignable to type 'string'. tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(52,3): error TS2322: Type '123' is not assignable to type 'T[keyof T]'. @@ -112,7 +113,8 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(108,5): error TS23 function f10(obj: T, k1: string, k2: keyof Item, k3: keyof T, k4: K) { obj[k1] = 123; // Error ~~~~~~~ -!!! error TS7017: Element implicitly has an 'any' type because type 'Item' has no index signature. +!!! error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Item'. +!!! error TS7053: No index signature with a parameter of type 'string' was found on type 'Item'. obj[k2] = 123; // Error ~~~~~~~ !!! error TS2322: Type '123' is not assignable to type 'string & number'. @@ -220,11 +222,12 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(108,5): error TS23 let y: ReadonlyArray[K] = 'abc'; } - // Repro from #31439 + // Repro from #31439 and #31691 export class c { [x: string]: string; constructor() { + this.a = "b"; this["a"] = "b"; } } diff --git a/tests/baselines/reference/keyofAndIndexedAccess2.js b/tests/baselines/reference/keyofAndIndexedAccess2.js index 7547a3f84c5..91cf2c89ff2 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess2.js +++ b/tests/baselines/reference/keyofAndIndexedAccess2.js @@ -137,11 +137,12 @@ function fn4() { let y: ReadonlyArray[K] = 'abc'; } -// Repro from #31439 +// Repro from #31439 and #31691 export class c { [x: string]: string; constructor() { + this.a = "b"; this["a"] = "b"; } } @@ -245,9 +246,10 @@ function fn4() { let x = 'abc'; let y = 'abc'; } -// Repro from #31439 +// Repro from #31439 and #31691 export class c { constructor() { + this.a = "b"; this["a"] = "b"; } } diff --git a/tests/baselines/reference/keyofAndIndexedAccess2.symbols b/tests/baselines/reference/keyofAndIndexedAccess2.symbols index 91602f93e1d..4a7721ff801 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess2.symbols +++ b/tests/baselines/reference/keyofAndIndexedAccess2.symbols @@ -503,7 +503,7 @@ function fn4() { >K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 133, 13)) } -// Repro from #31439 +// Repro from #31439 and #31691 export class c { >c : Symbol(c, Decl(keyofAndIndexedAccess2.ts, 136, 1)) @@ -512,6 +512,9 @@ export class c { >x : Symbol(x, Decl(keyofAndIndexedAccess2.ts, 141, 3)) constructor() { + this.a = "b"; +>this : Symbol(c, Decl(keyofAndIndexedAccess2.ts, 136, 1)) + this["a"] = "b"; >this : Symbol(c, Decl(keyofAndIndexedAccess2.ts, 136, 1)) } @@ -520,44 +523,44 @@ export class c { // Repro from #31385 type Foo = { [key: string]: { [K in keyof T]: K }[keyof T] }; ->Foo : Symbol(Foo, Decl(keyofAndIndexedAccess2.ts, 145, 1)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 149, 9)) ->key : Symbol(key, Decl(keyofAndIndexedAccess2.ts, 149, 17)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 149, 34)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 149, 9)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 149, 34)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 149, 9)) +>Foo : Symbol(Foo, Decl(keyofAndIndexedAccess2.ts, 146, 1)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 150, 9)) +>key : Symbol(key, Decl(keyofAndIndexedAccess2.ts, 150, 17)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 150, 34)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 150, 9)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 150, 34)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 150, 9)) type Bar = { [key: string]: { [K in keyof T]: [K] }[keyof T] }; ->Bar : Symbol(Bar, Decl(keyofAndIndexedAccess2.ts, 149, 64)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 151, 9)) ->key : Symbol(key, Decl(keyofAndIndexedAccess2.ts, 151, 17)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 151, 34)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 151, 9)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 151, 34)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 151, 9)) +>Bar : Symbol(Bar, Decl(keyofAndIndexedAccess2.ts, 150, 64)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 152, 9)) +>key : Symbol(key, Decl(keyofAndIndexedAccess2.ts, 152, 17)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 152, 34)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 152, 9)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 152, 34)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 152, 9)) type Baz> = { [K in keyof Q]: T[Q[K]] }; ->Baz : Symbol(Baz, Decl(keyofAndIndexedAccess2.ts, 151, 66)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 153, 9)) ->Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 153, 11)) ->Foo : Symbol(Foo, Decl(keyofAndIndexedAccess2.ts, 145, 1)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 153, 9)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 153, 35)) ->Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 153, 11)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 153, 9)) ->Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 153, 11)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 153, 35)) +>Baz : Symbol(Baz, Decl(keyofAndIndexedAccess2.ts, 152, 66)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 154, 9)) +>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 154, 11)) +>Foo : Symbol(Foo, Decl(keyofAndIndexedAccess2.ts, 146, 1)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 154, 9)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 154, 35)) +>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 154, 11)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 154, 9)) +>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 154, 11)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 154, 35)) type Qux> = { [K in keyof Q]: T[Q[K]["0"]] }; ->Qux : Symbol(Qux, Decl(keyofAndIndexedAccess2.ts, 153, 60)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 155, 9)) ->Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 155, 11)) ->Bar : Symbol(Bar, Decl(keyofAndIndexedAccess2.ts, 149, 64)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 155, 9)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 155, 35)) ->Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 155, 11)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 155, 9)) ->Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 155, 11)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 155, 35)) +>Qux : Symbol(Qux, Decl(keyofAndIndexedAccess2.ts, 154, 60)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 156, 9)) +>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 156, 11)) +>Bar : Symbol(Bar, Decl(keyofAndIndexedAccess2.ts, 150, 64)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 156, 9)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 156, 35)) +>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 156, 11)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 156, 9)) +>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 156, 11)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 156, 35)) diff --git a/tests/baselines/reference/keyofAndIndexedAccess2.types b/tests/baselines/reference/keyofAndIndexedAccess2.types index 45cf1d4bad5..a6d83154665 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess2.types +++ b/tests/baselines/reference/keyofAndIndexedAccess2.types @@ -499,7 +499,7 @@ function fn4() { >'abc' : "abc" } -// Repro from #31439 +// Repro from #31439 and #31691 export class c { >c : c @@ -508,6 +508,13 @@ export class c { >x : string constructor() { + this.a = "b"; +>this.a = "b" : "b" +>this.a : string +>this : this +>a : string +>"b" : "b" + this["a"] = "b"; >this["a"] = "b" : "b" >this["a"] : string diff --git a/tests/baselines/reference/noImplicitAnyForIn.errors.txt b/tests/baselines/reference/noImplicitAnyForIn.errors.txt index b384735d82e..c66a7e07f96 100644 --- a/tests/baselines/reference/noImplicitAnyForIn.errors.txt +++ b/tests/baselines/reference/noImplicitAnyForIn.errors.txt @@ -1,5 +1,7 @@ -tests/cases/compiler/noImplicitAnyForIn.ts(7,18): error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. -tests/cases/compiler/noImplicitAnyForIn.ts(14,18): error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. +tests/cases/compiler/noImplicitAnyForIn.ts(7,18): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'. + No index signature with a parameter of type 'string' was found on type '{}'. +tests/cases/compiler/noImplicitAnyForIn.ts(14,18): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'. + No index signature with a parameter of type 'string' was found on type '{}'. tests/cases/compiler/noImplicitAnyForIn.ts(28,5): error TS7005: Variable 'n' implicitly has an 'any[][]' type. tests/cases/compiler/noImplicitAnyForIn.ts(30,6): error TS2405: The left-hand side of a 'for...in' statement must be of type 'string' or 'any'. @@ -13,7 +15,8 @@ tests/cases/compiler/noImplicitAnyForIn.ts(30,6): error TS2405: The left-hand si //Should yield an implicit 'any' error var _j = x[i][j]; ~~~~~~~ -!!! error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. +!!! error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'. +!!! error TS7053: No index signature with a parameter of type 'string' was found on type '{}'. } for (var k in x[0]) { @@ -22,7 +25,8 @@ tests/cases/compiler/noImplicitAnyForIn.ts(30,6): error TS2405: The left-hand si //Should yield an implicit 'any' error var k2 = k1[k]; ~~~~~ -!!! error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. +!!! error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'. +!!! error TS7053: No index signature with a parameter of type 'string' was found on type '{}'. } } diff --git a/tests/baselines/reference/noImplicitAnyIndexing.errors.txt b/tests/baselines/reference/noImplicitAnyIndexing.errors.txt index 8d1d3ea6c46..f9631f29aa1 100644 --- a/tests/baselines/reference/noImplicitAnyIndexing.errors.txt +++ b/tests/baselines/reference/noImplicitAnyIndexing.errors.txt @@ -1,7 +1,9 @@ tests/cases/compiler/noImplicitAnyIndexing.ts(12,37): error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'. -tests/cases/compiler/noImplicitAnyIndexing.ts(19,9): error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. -tests/cases/compiler/noImplicitAnyIndexing.ts(22,9): error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. -tests/cases/compiler/noImplicitAnyIndexing.ts(30,10): error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. +tests/cases/compiler/noImplicitAnyIndexing.ts(19,9): error TS7053: Element implicitly has an 'any' type because expression of type '"hi"' can't be used to index type '{}'. + Property 'hi' does not exist on type '{}'. +tests/cases/compiler/noImplicitAnyIndexing.ts(22,9): error TS7053: Element implicitly has an 'any' type because expression of type '10' can't be used to index type '{}'. + Property '10' does not exist on type '{}'. +tests/cases/compiler/noImplicitAnyIndexing.ts(30,10): error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type '{}'. ==== tests/cases/compiler/noImplicitAnyIndexing.ts (4 errors) ==== @@ -27,12 +29,14 @@ tests/cases/compiler/noImplicitAnyIndexing.ts(30,10): error TS7017: Element impl // Should report an implicit 'any'. var x = {}["hi"]; ~~~~~~~~ -!!! error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. +!!! error TS7053: Element implicitly has an 'any' type because expression of type '"hi"' can't be used to index type '{}'. +!!! error TS7053: Property 'hi' does not exist on type '{}'. // Should report an implicit 'any'. var y = {}[10]; ~~~~~~ -!!! error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. +!!! error TS7053: Element implicitly has an 'any' type because expression of type '10' can't be used to index type '{}'. +!!! error TS7053: Property '10' does not exist on type '{}'. var hi: any = "hi"; @@ -42,7 +46,7 @@ tests/cases/compiler/noImplicitAnyIndexing.ts(30,10): error TS7017: Element impl // Should report an implicit 'any'. var z1 = emptyObj[hi]; ~~~~~~~~~~~~ -!!! error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. +!!! error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type '{}'. var z2 = (emptyObj)[hi]; interface MyMap { diff --git a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.errors.txt b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.errors.txt index 6df52aea46a..0d2fc1b860e 100644 --- a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.errors.txt +++ b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.errors.txt @@ -1,16 +1,29 @@ -tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(1,9): error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(1,9): error TS7053: Element implicitly has an 'any' type because expression of type '"hello"' can't be used to index type '{}'. + Property 'hello' does not exist on type '{}'. tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(7,1): error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; }' has no index signature. Did you mean to call 'get' ? tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(8,13): error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; }' has no index signature. Did you mean to call 'get' ? -tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(13,13): error TS7017: Element implicitly has an 'any' type because type '{ set: (key: string) => string; }' has no index signature. +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(13,13): error TS7053: Element implicitly has an 'any' type because expression of type '"hello"' can't be used to index type '{ set: (key: string) => string; }'. + Property 'hello' does not exist on type '{ set: (key: string) => string; }'. tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(19,1): error TS7052: Element implicitly has an 'any' type because type '{ set: (key: string) => string; get: (key: string) => string; }' has no index signature. Did you mean to call 'set' ? tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(20,1): error TS7052: Element implicitly has an 'any' type because type '{ set: (key: string) => string; get: (key: string) => string; }' has no index signature. Did you mean to call 'set' ? tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(21,1): error TS7052: Element implicitly has an 'any' type because type '{ set: (key: string) => string; get: (key: string) => string; }' has no index signature. Did you mean to call 'set' ? +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(26,1): error TS7053: Element implicitly has an 'any' type because expression of type '"a" | "b" | "c"' can't be used to index type '{ a: number; }'. + Property 'b' does not exist on type '{ a: number; }'. +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(30,1): error TS7053: Element implicitly has an 'any' type because expression of type '"c"' can't be used to index type '{ a: number; }'. + Property 'c' does not exist on type '{ a: number; }'. +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(33,1): error TS7053: Element implicitly has an 'any' type because expression of type 'unique symbol' can't be used to index type '{ a: number; }'. + Property '[sym]' does not exist on type '{ a: number; }'. +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(37,1): error TS7053: Element implicitly has an 'any' type because expression of type 'NumEnum' can't be used to index type '{ a: number; }'. + Property '[NumEnum.a]' does not exist on type '{ a: number; }'. +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(42,1): error TS7053: Element implicitly has an 'any' type because expression of type 'StrEnum' can't be used to index type '{ a: number; }'. + Property '[StrEnum.b]' does not exist on type '{ a: number; }'. -==== tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts (7 errors) ==== +==== tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts (12 errors) ==== var a = {}["hello"]; ~~~~~~~~~~~ -!!! error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. +!!! error TS7053: Element implicitly has an 'any' type because expression of type '"hello"' can't be used to index type '{}'. +!!! error TS7053: Property 'hello' does not exist on type '{}'. var b: string = { '': 'foo' }['']; var c = { @@ -28,7 +41,8 @@ tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(21,1): error TS7052: }; const bar = d['hello']; ~~~~~~~~~~ -!!! error TS7017: Element implicitly has an 'any' type because type '{ set: (key: string) => string; }' has no index signature. +!!! error TS7053: Element implicitly has an 'any' type because expression of type '"hello"' can't be used to index type '{ set: (key: string) => string; }'. +!!! error TS7053: Property 'hello' does not exist on type '{ set: (key: string) => string; }'. var e = { set: (key: string) => 'foobar', @@ -44,4 +58,39 @@ tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(21,1): error TS7052: ~~~~~~~~~~ !!! error TS7052: Element implicitly has an 'any' type because type '{ set: (key: string) => string; get: (key: string) => string; }' has no index signature. Did you mean to call 'set' ? + const o = { a: 0 }; + + declare const k: "a" | "b" | "c"; + o[k]; + ~~~~ +!!! error TS7053: Element implicitly has an 'any' type because expression of type '"a" | "b" | "c"' can't be used to index type '{ a: number; }'. +!!! error TS7053: Property 'b' does not exist on type '{ a: number; }'. + + + declare const k2: "c"; + o[k2]; + ~~~~~ +!!! error TS7053: Element implicitly has an 'any' type because expression of type '"c"' can't be used to index type '{ a: number; }'. +!!! error TS7053: Property 'c' does not exist on type '{ a: number; }'. + + declare const sym : unique symbol; + o[sym]; + ~~~~~~ +!!! error TS7053: Element implicitly has an 'any' type because expression of type 'unique symbol' can't be used to index type '{ a: number; }'. +!!! error TS7053: Property '[sym]' does not exist on type '{ a: number; }'. + + enum NumEnum { a, b } + let numEnumKey: NumEnum; + o[numEnumKey]; + ~~~~~~~~~~~~~ +!!! error TS7053: Element implicitly has an 'any' type because expression of type 'NumEnum' can't be used to index type '{ a: number; }'. +!!! error TS7053: Property '[NumEnum.a]' does not exist on type '{ a: number; }'. + + + enum StrEnum { a = "a", b = "b" } + let strEnumKey: StrEnum; + o[strEnumKey]; + ~~~~~~~~~~~~~ +!!! error TS7053: Element implicitly has an 'any' type because expression of type 'StrEnum' can't be used to index type '{ a: number; }'. +!!! error TS7053: Property '[StrEnum.b]' does not exist on type '{ a: number; }'. \ No newline at end of file diff --git a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.js b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.js index a02740351cf..572d9f38caf 100644 --- a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.js +++ b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.js @@ -21,6 +21,26 @@ e['hello'] = 'modified'; e['hello'] += 1; e['hello'] ++; +const o = { a: 0 }; + +declare const k: "a" | "b" | "c"; +o[k]; + + +declare const k2: "c"; +o[k2]; + +declare const sym : unique symbol; +o[sym]; + +enum NumEnum { a, b } +let numEnumKey: NumEnum; +o[numEnumKey]; + + +enum StrEnum { a = "a", b = "b" } +let strEnumKey: StrEnum; +o[strEnumKey]; //// [noImplicitAnyStringIndexerOnObject.js] @@ -42,3 +62,21 @@ var e = { e['hello'] = 'modified'; e['hello'] += 1; e['hello']++; +var o = { a: 0 }; +o[k]; +o[k2]; +o[sym]; +var NumEnum; +(function (NumEnum) { + NumEnum[NumEnum["a"] = 0] = "a"; + NumEnum[NumEnum["b"] = 1] = "b"; +})(NumEnum || (NumEnum = {})); +var numEnumKey; +o[numEnumKey]; +var StrEnum; +(function (StrEnum) { + StrEnum["a"] = "a"; + StrEnum["b"] = "b"; +})(StrEnum || (StrEnum = {})); +var strEnumKey; +o[strEnumKey]; diff --git a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.symbols b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.symbols index f86c0d14b6f..307144b8563 100644 --- a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.symbols +++ b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.symbols @@ -55,4 +55,56 @@ e['hello'] += 1; e['hello'] ++; >e : Symbol(e, Decl(noImplicitAnyStringIndexerOnObject.ts, 14, 3)) +const o = { a: 0 }; +>o : Symbol(o, Decl(noImplicitAnyStringIndexerOnObject.ts, 22, 5)) +>a : Symbol(a, Decl(noImplicitAnyStringIndexerOnObject.ts, 22, 11)) + +declare const k: "a" | "b" | "c"; +>k : Symbol(k, Decl(noImplicitAnyStringIndexerOnObject.ts, 24, 13)) + +o[k]; +>o : Symbol(o, Decl(noImplicitAnyStringIndexerOnObject.ts, 22, 5)) +>k : Symbol(k, Decl(noImplicitAnyStringIndexerOnObject.ts, 24, 13)) + + +declare const k2: "c"; +>k2 : Symbol(k2, Decl(noImplicitAnyStringIndexerOnObject.ts, 28, 13)) + +o[k2]; +>o : Symbol(o, Decl(noImplicitAnyStringIndexerOnObject.ts, 22, 5)) +>k2 : Symbol(k2, Decl(noImplicitAnyStringIndexerOnObject.ts, 28, 13)) + +declare const sym : unique symbol; +>sym : Symbol(sym, Decl(noImplicitAnyStringIndexerOnObject.ts, 31, 13)) + +o[sym]; +>o : Symbol(o, Decl(noImplicitAnyStringIndexerOnObject.ts, 22, 5)) +>sym : Symbol(sym, Decl(noImplicitAnyStringIndexerOnObject.ts, 31, 13)) + +enum NumEnum { a, b } +>NumEnum : Symbol(NumEnum, Decl(noImplicitAnyStringIndexerOnObject.ts, 32, 7)) +>a : Symbol(NumEnum.a, Decl(noImplicitAnyStringIndexerOnObject.ts, 34, 14)) +>b : Symbol(NumEnum.b, Decl(noImplicitAnyStringIndexerOnObject.ts, 34, 17)) + +let numEnumKey: NumEnum; +>numEnumKey : Symbol(numEnumKey, Decl(noImplicitAnyStringIndexerOnObject.ts, 35, 3)) +>NumEnum : Symbol(NumEnum, Decl(noImplicitAnyStringIndexerOnObject.ts, 32, 7)) + +o[numEnumKey]; +>o : Symbol(o, Decl(noImplicitAnyStringIndexerOnObject.ts, 22, 5)) +>numEnumKey : Symbol(numEnumKey, Decl(noImplicitAnyStringIndexerOnObject.ts, 35, 3)) + + +enum StrEnum { a = "a", b = "b" } +>StrEnum : Symbol(StrEnum, Decl(noImplicitAnyStringIndexerOnObject.ts, 36, 14)) +>a : Symbol(StrEnum.a, Decl(noImplicitAnyStringIndexerOnObject.ts, 39, 14)) +>b : Symbol(StrEnum.b, Decl(noImplicitAnyStringIndexerOnObject.ts, 39, 23)) + +let strEnumKey: StrEnum; +>strEnumKey : Symbol(strEnumKey, Decl(noImplicitAnyStringIndexerOnObject.ts, 40, 3)) +>StrEnum : Symbol(StrEnum, Decl(noImplicitAnyStringIndexerOnObject.ts, 36, 14)) + +o[strEnumKey]; +>o : Symbol(o, Decl(noImplicitAnyStringIndexerOnObject.ts, 22, 5)) +>strEnumKey : Symbol(strEnumKey, Decl(noImplicitAnyStringIndexerOnObject.ts, 40, 3)) diff --git a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.types b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.types index dcf01d8c5e8..fa74a192248 100644 --- a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.types +++ b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.types @@ -89,4 +89,63 @@ e['hello'] ++; >e : { set: (key: string) => string; get: (key: string) => string; } >'hello' : "hello" +const o = { a: 0 }; +>o : { a: number; } +>{ a: 0 } : { a: number; } +>a : number +>0 : 0 + +declare const k: "a" | "b" | "c"; +>k : "a" | "b" | "c" + +o[k]; +>o[k] : any +>o : { a: number; } +>k : "a" | "b" | "c" + + +declare const k2: "c"; +>k2 : "c" + +o[k2]; +>o[k2] : any +>o : { a: number; } +>k2 : "c" + +declare const sym : unique symbol; +>sym : unique symbol + +o[sym]; +>o[sym] : any +>o : { a: number; } +>sym : unique symbol + +enum NumEnum { a, b } +>NumEnum : NumEnum +>a : NumEnum.a +>b : NumEnum.b + +let numEnumKey: NumEnum; +>numEnumKey : NumEnum + +o[numEnumKey]; +>o[numEnumKey] : any +>o : { a: number; } +>numEnumKey : NumEnum + + +enum StrEnum { a = "a", b = "b" } +>StrEnum : StrEnum +>a : StrEnum.a +>"a" : "a" +>b : StrEnum.b +>"b" : "b" + +let strEnumKey: StrEnum; +>strEnumKey : StrEnum + +o[strEnumKey]; +>o[strEnumKey] : any +>o : { a: number; } +>strEnumKey : StrEnum diff --git a/tests/baselines/reference/noImplicitThisBigThis.js b/tests/baselines/reference/noImplicitThisBigThis.js new file mode 100644 index 00000000000..f2e633f2dcf --- /dev/null +++ b/tests/baselines/reference/noImplicitThisBigThis.js @@ -0,0 +1,115 @@ +//// [noImplicitThisBigThis.ts] +// https://github.com/microsoft/TypeScript/issues/29902 + +function createObj() { + return { + func1() { + return this; + }, + func2() { + return this; + }, + func3() { + return this; + } + }; +} + +function createObjNoCrash() { + return { + func1() { + return this; + }, + func2() { + return this; + }, + func3() { + return this; + }, + func4() { + return this; + }, + func5() { + return this; + }, + func6() { + return this; + }, + func7() { + return this; + }, + func8() { + return this; + }, + func9() { + return this; + } + }; +} + + +//// [noImplicitThisBigThis.js] +// https://github.com/microsoft/TypeScript/issues/29902 +function createObj() { + return { + func1: function () { + return this; + }, + func2: function () { + return this; + }, + func3: function () { + return this; + } + }; +} +function createObjNoCrash() { + return { + func1: function () { + return this; + }, + func2: function () { + return this; + }, + func3: function () { + return this; + }, + func4: function () { + return this; + }, + func5: function () { + return this; + }, + func6: function () { + return this; + }, + func7: function () { + return this; + }, + func8: function () { + return this; + }, + func9: function () { + return this; + } + }; +} + + +//// [noImplicitThisBigThis.d.ts] +declare function createObj(): { + func1(): any; + func2(): any; + func3(): any; +}; +declare function createObjNoCrash(): { + func1(): any; + func2(): any; + func3(): any; + func4(): any; + func5(): any; + func6(): any; + func7(): any; + func8(): any; + func9(): any; +}; diff --git a/tests/baselines/reference/noImplicitThisBigThis.symbols b/tests/baselines/reference/noImplicitThisBigThis.symbols new file mode 100644 index 00000000000..9f0c8c1bf24 --- /dev/null +++ b/tests/baselines/reference/noImplicitThisBigThis.symbols @@ -0,0 +1,99 @@ +=== tests/cases/compiler/noImplicitThisBigThis.ts === +// https://github.com/microsoft/TypeScript/issues/29902 + +function createObj() { +>createObj : Symbol(createObj, Decl(noImplicitThisBigThis.ts, 0, 0)) + + return { + func1() { +>func1 : Symbol(func1, Decl(noImplicitThisBigThis.ts, 3, 12)) + + return this; +>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 3, 10)) + + }, + func2() { +>func2 : Symbol(func2, Decl(noImplicitThisBigThis.ts, 6, 10)) + + return this; +>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 3, 10)) + + }, + func3() { +>func3 : Symbol(func3, Decl(noImplicitThisBigThis.ts, 9, 10)) + + return this; +>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 3, 10)) + } + }; +} + +function createObjNoCrash() { +>createObjNoCrash : Symbol(createObjNoCrash, Decl(noImplicitThisBigThis.ts, 14, 1)) + + return { + func1() { +>func1 : Symbol(func1, Decl(noImplicitThisBigThis.ts, 17, 12)) + + return this; +>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10)) + + }, + func2() { +>func2 : Symbol(func2, Decl(noImplicitThisBigThis.ts, 20, 10)) + + return this; +>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10)) + + }, + func3() { +>func3 : Symbol(func3, Decl(noImplicitThisBigThis.ts, 23, 10)) + + return this; +>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10)) + + }, + func4() { +>func4 : Symbol(func4, Decl(noImplicitThisBigThis.ts, 26, 10)) + + return this; +>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10)) + + }, + func5() { +>func5 : Symbol(func5, Decl(noImplicitThisBigThis.ts, 29, 10)) + + return this; +>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10)) + + }, + func6() { +>func6 : Symbol(func6, Decl(noImplicitThisBigThis.ts, 32, 10)) + + return this; +>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10)) + + }, + func7() { +>func7 : Symbol(func7, Decl(noImplicitThisBigThis.ts, 35, 10)) + + return this; +>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10)) + + }, + func8() { +>func8 : Symbol(func8, Decl(noImplicitThisBigThis.ts, 38, 10)) + + return this; +>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10)) + + }, + func9() { +>func9 : Symbol(func9, Decl(noImplicitThisBigThis.ts, 41, 10)) + + return this; +>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10)) + } + }; +} + diff --git a/tests/baselines/reference/noImplicitThisBigThis.types b/tests/baselines/reference/noImplicitThisBigThis.types new file mode 100644 index 00000000000..4e1731aebc7 --- /dev/null +++ b/tests/baselines/reference/noImplicitThisBigThis.types @@ -0,0 +1,103 @@ +=== tests/cases/compiler/noImplicitThisBigThis.ts === +// https://github.com/microsoft/TypeScript/issues/29902 + +function createObj() { +>createObj : () => { func1(): any; func2(): any; func3(): any; } + + return { +>{ func1() { return this; }, func2() { return this; }, func3() { return this; } } : { func1(): { func1(): any; func2(): any; func3(): any; }; func2(): { func1(): any; func2(): any; func3(): any; }; func3(): { func1(): any; func2(): any; func3(): any; }; } + + func1() { +>func1 : () => { func1(): any; func2(): any; func3(): any; } + + return this; +>this : { func1(): { func1(): any; func2(): any; func3(): any; }; func2(): { func1(): any; func2(): any; func3(): any; }; func3(): { func1(): any; func2(): any; func3(): any; }; } + + }, + func2() { +>func2 : () => { func1(): any; func2(): any; func3(): any; } + + return this; +>this : { func1(): { func1(): any; func2(): any; func3(): any; }; func2(): { func1(): any; func2(): any; func3(): any; }; func3(): { func1(): any; func2(): any; func3(): any; }; } + + }, + func3() { +>func3 : () => { func1(): any; func2(): any; func3(): any; } + + return this; +>this : { func1(): { func1(): any; func2(): any; func3(): any; }; func2(): { func1(): any; func2(): any; func3(): any; }; func3(): { func1(): any; func2(): any; func3(): any; }; } + } + }; +} + +function createObjNoCrash() { +>createObjNoCrash : () => { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; } + + return { +>{ func1() { return this; }, func2() { return this; }, func3() { return this; }, func4() { return this; }, func5() { return this; }, func6() { return this; }, func7() { return this; }, func8() { return this; }, func9() { return this; } } : { func1(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func2(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func3(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func4(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func5(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func6(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func7(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func8(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func9(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; } + + func1() { +>func1 : () => { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; } + + return this; +>this : { func1(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func2(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func3(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func4(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func5(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func6(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func7(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func8(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func9(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; } + + }, + func2() { +>func2 : () => { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; } + + return this; +>this : { func1(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func2(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func3(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func4(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func5(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func6(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func7(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func8(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func9(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; } + + }, + func3() { +>func3 : () => { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; } + + return this; +>this : { func1(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func2(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func3(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func4(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func5(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func6(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func7(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func8(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func9(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; } + + }, + func4() { +>func4 : () => { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; } + + return this; +>this : { func1(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func2(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func3(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func4(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func5(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func6(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func7(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func8(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func9(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; } + + }, + func5() { +>func5 : () => { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; } + + return this; +>this : { func1(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func2(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func3(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func4(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func5(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func6(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func7(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func8(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func9(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; } + + }, + func6() { +>func6 : () => { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; } + + return this; +>this : { func1(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func2(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func3(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func4(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func5(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func6(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func7(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func8(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func9(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; } + + }, + func7() { +>func7 : () => { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; } + + return this; +>this : { func1(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func2(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func3(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func4(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func5(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func6(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func7(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func8(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func9(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; } + + }, + func8() { +>func8 : () => { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; } + + return this; +>this : { func1(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func2(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func3(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func4(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func5(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func6(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func7(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func8(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func9(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; } + + }, + func9() { +>func9 : () => { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; } + + return this; +>this : { func1(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func2(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func3(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func4(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func5(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func6(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func7(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func8(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; func9(): { func1(): any; func2(): any; func3(): any; func4(): any; func5(): any; func6(): any; func7(): any; func8(): any; func9(): any; }; } + } + }; +} + diff --git a/tests/baselines/reference/nonPrimitiveIndexingWithForInNoImplicitAny.errors.txt b/tests/baselines/reference/nonPrimitiveIndexingWithForInNoImplicitAny.errors.txt index f7f2ee3db16..07f52bf3e6f 100644 --- a/tests/baselines/reference/nonPrimitiveIndexingWithForInNoImplicitAny.errors.txt +++ b/tests/baselines/reference/nonPrimitiveIndexingWithForInNoImplicitAny.errors.txt @@ -1,4 +1,5 @@ -tests/cases/conformance/types/nonPrimitive/nonPrimitiveIndexingWithForInNoImplicitAny.ts(4,17): error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveIndexingWithForInNoImplicitAny.ts(4,17): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'. + No index signature with a parameter of type 'string' was found on type '{}'. ==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveIndexingWithForInNoImplicitAny.ts (1 errors) ==== @@ -7,6 +8,7 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveIndexingWithForInNoImplic for (var key in a) { var value = a[key]; // error ~~~~~~ -!!! error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. +!!! error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'. +!!! error TS7053: No index signature with a parameter of type 'string' was found on type '{}'. } \ No newline at end of file diff --git a/tests/baselines/reference/normalizedIntersectionTooComplex.errors.txt b/tests/baselines/reference/normalizedIntersectionTooComplex.errors.txt new file mode 100644 index 00000000000..64e7d7f00c5 --- /dev/null +++ b/tests/baselines/reference/normalizedIntersectionTooComplex.errors.txt @@ -0,0 +1,46 @@ +tests/cases/compiler/normalizedIntersectionTooComplex.ts(36,40): error TS7006: Parameter 'x' implicitly has an 'any' type. +tests/cases/compiler/normalizedIntersectionTooComplex.ts(36,40): error TS2590: Expression produces a union type that is too complex to represent. + + +==== tests/cases/compiler/normalizedIntersectionTooComplex.ts (2 errors) ==== + // Repro from #30050 + + interface Obj { + ref: T; + } + interface Func { + (x: T): void; + } + type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; + type CtorOf = (arg: UnionToIntersection) => T; + + interface Big { + "0": { common?: string; "0"?: number, ref?: Obj | Func; } + "1": { common?: string; "1"?: number, ref?: Obj | Func; } + "2": { common?: string; "2"?: number, ref?: Obj | Func; } + "3": { common?: string; "3"?: number, ref?: Obj | Func; } + "4": { common?: string; "4"?: number, ref?: Obj | Func; } + "5": { common?: string; "5"?: number, ref?: Obj | Func; } + "6": { common?: string; "6"?: number, ref?: Obj | Func; } + "7": { common?: string; "7"?: number, ref?: Obj | Func; } + "8": { common?: string; "8"?: number, ref?: Obj | Func; } + "9": { common?: string; "9"?: number, ref?: Obj | Func; } + "10": { common?: string; "10"?: number, ref?: Obj | Func; } + "11": { common?: string; "11"?: number, ref?: Obj | Func; } + "12": { common?: string; "12"?: number, ref?: Obj | Func; } + "13": { common?: string; "13"?: number, ref?: Obj | Func; } + "14": { common?: string; "14"?: number, ref?: Obj | Func; } + "15": { common?: string; "15"?: number, ref?: Obj | Func; } + "16": { common?: string; "16"?: number, ref?: Obj | Func; } + "17": { common?: string; "17"?: number, ref?: Obj | Func; } + } + declare function getCtor(comp: T): CtorOf + + declare var all: keyof Big; + const ctor = getCtor(all); + const comp = ctor({ common: "ok", ref: x => console.log(x) }); + ~ +!!! error TS7006: Parameter 'x' implicitly has an 'any' type. + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2590: Expression produces a union type that is too complex to represent. + \ No newline at end of file diff --git a/tests/baselines/reference/normalizedIntersectionTooComplex.js b/tests/baselines/reference/normalizedIntersectionTooComplex.js new file mode 100644 index 00000000000..d55189f7a1c --- /dev/null +++ b/tests/baselines/reference/normalizedIntersectionTooComplex.js @@ -0,0 +1,44 @@ +//// [normalizedIntersectionTooComplex.ts] +// Repro from #30050 + +interface Obj { + ref: T; +} +interface Func { + (x: T): void; +} +type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; +type CtorOf = (arg: UnionToIntersection) => T; + +interface Big { + "0": { common?: string; "0"?: number, ref?: Obj | Func; } + "1": { common?: string; "1"?: number, ref?: Obj | Func; } + "2": { common?: string; "2"?: number, ref?: Obj | Func; } + "3": { common?: string; "3"?: number, ref?: Obj | Func; } + "4": { common?: string; "4"?: number, ref?: Obj | Func; } + "5": { common?: string; "5"?: number, ref?: Obj | Func; } + "6": { common?: string; "6"?: number, ref?: Obj | Func; } + "7": { common?: string; "7"?: number, ref?: Obj | Func; } + "8": { common?: string; "8"?: number, ref?: Obj | Func; } + "9": { common?: string; "9"?: number, ref?: Obj | Func; } + "10": { common?: string; "10"?: number, ref?: Obj | Func; } + "11": { common?: string; "11"?: number, ref?: Obj | Func; } + "12": { common?: string; "12"?: number, ref?: Obj | Func; } + "13": { common?: string; "13"?: number, ref?: Obj | Func; } + "14": { common?: string; "14"?: number, ref?: Obj | Func; } + "15": { common?: string; "15"?: number, ref?: Obj | Func; } + "16": { common?: string; "16"?: number, ref?: Obj | Func; } + "17": { common?: string; "17"?: number, ref?: Obj | Func; } +} +declare function getCtor(comp: T): CtorOf + +declare var all: keyof Big; +const ctor = getCtor(all); +const comp = ctor({ common: "ok", ref: x => console.log(x) }); + + +//// [normalizedIntersectionTooComplex.js] +"use strict"; +// Repro from #30050 +var ctor = getCtor(all); +var comp = ctor({ common: "ok", ref: function (x) { return console.log(x); } }); diff --git a/tests/baselines/reference/normalizedIntersectionTooComplex.symbols b/tests/baselines/reference/normalizedIntersectionTooComplex.symbols new file mode 100644 index 00000000000..0854ef907df --- /dev/null +++ b/tests/baselines/reference/normalizedIntersectionTooComplex.symbols @@ -0,0 +1,250 @@ +=== tests/cases/compiler/normalizedIntersectionTooComplex.ts === +// Repro from #30050 + +interface Obj { +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>T : Symbol(T, Decl(normalizedIntersectionTooComplex.ts, 2, 14)) + + ref: T; +>ref : Symbol(Obj.ref, Decl(normalizedIntersectionTooComplex.ts, 2, 18)) +>T : Symbol(T, Decl(normalizedIntersectionTooComplex.ts, 2, 14)) +} +interface Func { +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>T : Symbol(T, Decl(normalizedIntersectionTooComplex.ts, 5, 15)) + + (x: T): void; +>x : Symbol(x, Decl(normalizedIntersectionTooComplex.ts, 6, 2)) +>T : Symbol(T, Decl(normalizedIntersectionTooComplex.ts, 5, 15)) +} +type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; +>UnionToIntersection : Symbol(UnionToIntersection, Decl(normalizedIntersectionTooComplex.ts, 7, 1)) +>U : Symbol(U, Decl(normalizedIntersectionTooComplex.ts, 8, 25)) +>U : Symbol(U, Decl(normalizedIntersectionTooComplex.ts, 8, 25)) +>k : Symbol(k, Decl(normalizedIntersectionTooComplex.ts, 8, 48)) +>U : Symbol(U, Decl(normalizedIntersectionTooComplex.ts, 8, 25)) +>k : Symbol(k, Decl(normalizedIntersectionTooComplex.ts, 8, 81)) +>I : Symbol(I, Decl(normalizedIntersectionTooComplex.ts, 8, 89)) +>I : Symbol(I, Decl(normalizedIntersectionTooComplex.ts, 8, 89)) + +type CtorOf = (arg: UnionToIntersection) => T; +>CtorOf : Symbol(CtorOf, Decl(normalizedIntersectionTooComplex.ts, 8, 114)) +>T : Symbol(T, Decl(normalizedIntersectionTooComplex.ts, 9, 12)) +>arg : Symbol(arg, Decl(normalizedIntersectionTooComplex.ts, 9, 18)) +>UnionToIntersection : Symbol(UnionToIntersection, Decl(normalizedIntersectionTooComplex.ts, 7, 1)) +>T : Symbol(T, Decl(normalizedIntersectionTooComplex.ts, 9, 12)) +>T : Symbol(T, Decl(normalizedIntersectionTooComplex.ts, 9, 12)) + +interface Big { +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "0": { common?: string; "0"?: number, ref?: Obj | Func; } +>"0" : Symbol(Big["0"], Decl(normalizedIntersectionTooComplex.ts, 11, 15)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 12, 10)) +>"0" : Symbol("0", Decl(normalizedIntersectionTooComplex.ts, 12, 27)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 12, 41)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "1": { common?: string; "1"?: number, ref?: Obj | Func; } +>"1" : Symbol(Big["1"], Decl(normalizedIntersectionTooComplex.ts, 12, 81)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 13, 10)) +>"1" : Symbol("1", Decl(normalizedIntersectionTooComplex.ts, 13, 27)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 13, 41)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "2": { common?: string; "2"?: number, ref?: Obj | Func; } +>"2" : Symbol(Big["2"], Decl(normalizedIntersectionTooComplex.ts, 13, 81)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 14, 10)) +>"2" : Symbol("2", Decl(normalizedIntersectionTooComplex.ts, 14, 27)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 14, 41)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "3": { common?: string; "3"?: number, ref?: Obj | Func; } +>"3" : Symbol(Big["3"], Decl(normalizedIntersectionTooComplex.ts, 14, 81)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 15, 10)) +>"3" : Symbol("3", Decl(normalizedIntersectionTooComplex.ts, 15, 27)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 15, 41)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "4": { common?: string; "4"?: number, ref?: Obj | Func; } +>"4" : Symbol(Big["4"], Decl(normalizedIntersectionTooComplex.ts, 15, 81)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 16, 10)) +>"4" : Symbol("4", Decl(normalizedIntersectionTooComplex.ts, 16, 27)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 16, 41)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "5": { common?: string; "5"?: number, ref?: Obj | Func; } +>"5" : Symbol(Big["5"], Decl(normalizedIntersectionTooComplex.ts, 16, 81)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 17, 10)) +>"5" : Symbol("5", Decl(normalizedIntersectionTooComplex.ts, 17, 27)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 17, 41)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "6": { common?: string; "6"?: number, ref?: Obj | Func; } +>"6" : Symbol(Big["6"], Decl(normalizedIntersectionTooComplex.ts, 17, 81)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 18, 10)) +>"6" : Symbol("6", Decl(normalizedIntersectionTooComplex.ts, 18, 27)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 18, 41)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "7": { common?: string; "7"?: number, ref?: Obj | Func; } +>"7" : Symbol(Big["7"], Decl(normalizedIntersectionTooComplex.ts, 18, 81)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 19, 10)) +>"7" : Symbol("7", Decl(normalizedIntersectionTooComplex.ts, 19, 27)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 19, 41)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "8": { common?: string; "8"?: number, ref?: Obj | Func; } +>"8" : Symbol(Big["8"], Decl(normalizedIntersectionTooComplex.ts, 19, 81)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 20, 10)) +>"8" : Symbol("8", Decl(normalizedIntersectionTooComplex.ts, 20, 27)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 20, 41)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "9": { common?: string; "9"?: number, ref?: Obj | Func; } +>"9" : Symbol(Big["9"], Decl(normalizedIntersectionTooComplex.ts, 20, 81)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 21, 10)) +>"9" : Symbol("9", Decl(normalizedIntersectionTooComplex.ts, 21, 27)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 21, 41)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "10": { common?: string; "10"?: number, ref?: Obj | Func; } +>"10" : Symbol(Big["10"], Decl(normalizedIntersectionTooComplex.ts, 21, 81)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 22, 11)) +>"10" : Symbol("10", Decl(normalizedIntersectionTooComplex.ts, 22, 28)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 22, 43)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "11": { common?: string; "11"?: number, ref?: Obj | Func; } +>"11" : Symbol(Big["11"], Decl(normalizedIntersectionTooComplex.ts, 22, 85)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 23, 11)) +>"11" : Symbol("11", Decl(normalizedIntersectionTooComplex.ts, 23, 28)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 23, 43)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "12": { common?: string; "12"?: number, ref?: Obj | Func; } +>"12" : Symbol(Big["12"], Decl(normalizedIntersectionTooComplex.ts, 23, 85)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 24, 11)) +>"12" : Symbol("12", Decl(normalizedIntersectionTooComplex.ts, 24, 28)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 24, 43)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "13": { common?: string; "13"?: number, ref?: Obj | Func; } +>"13" : Symbol(Big["13"], Decl(normalizedIntersectionTooComplex.ts, 24, 85)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 25, 11)) +>"13" : Symbol("13", Decl(normalizedIntersectionTooComplex.ts, 25, 28)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 25, 43)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "14": { common?: string; "14"?: number, ref?: Obj | Func; } +>"14" : Symbol(Big["14"], Decl(normalizedIntersectionTooComplex.ts, 25, 85)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 26, 11)) +>"14" : Symbol("14", Decl(normalizedIntersectionTooComplex.ts, 26, 28)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 26, 43)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "15": { common?: string; "15"?: number, ref?: Obj | Func; } +>"15" : Symbol(Big["15"], Decl(normalizedIntersectionTooComplex.ts, 26, 85)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 27, 11)) +>"15" : Symbol("15", Decl(normalizedIntersectionTooComplex.ts, 27, 28)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 27, 43)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "16": { common?: string; "16"?: number, ref?: Obj | Func; } +>"16" : Symbol(Big["16"], Decl(normalizedIntersectionTooComplex.ts, 27, 85)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 28, 11)) +>"16" : Symbol("16", Decl(normalizedIntersectionTooComplex.ts, 28, 28)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 28, 43)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + + "17": { common?: string; "17"?: number, ref?: Obj | Func; } +>"17" : Symbol(Big["17"], Decl(normalizedIntersectionTooComplex.ts, 28, 85)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 29, 11)) +>"17" : Symbol("17", Decl(normalizedIntersectionTooComplex.ts, 29, 28)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 29, 43)) +>Obj : Symbol(Obj, Decl(normalizedIntersectionTooComplex.ts, 0, 0)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>Func : Symbol(Func, Decl(normalizedIntersectionTooComplex.ts, 4, 1)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +} +declare function getCtor(comp: T): CtorOf +>getCtor : Symbol(getCtor, Decl(normalizedIntersectionTooComplex.ts, 30, 1)) +>T : Symbol(T, Decl(normalizedIntersectionTooComplex.ts, 31, 25)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>comp : Symbol(comp, Decl(normalizedIntersectionTooComplex.ts, 31, 46)) +>T : Symbol(T, Decl(normalizedIntersectionTooComplex.ts, 31, 25)) +>CtorOf : Symbol(CtorOf, Decl(normalizedIntersectionTooComplex.ts, 8, 114)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) +>T : Symbol(T, Decl(normalizedIntersectionTooComplex.ts, 31, 25)) + +declare var all: keyof Big; +>all : Symbol(all, Decl(normalizedIntersectionTooComplex.ts, 33, 11)) +>Big : Symbol(Big, Decl(normalizedIntersectionTooComplex.ts, 9, 52)) + +const ctor = getCtor(all); +>ctor : Symbol(ctor, Decl(normalizedIntersectionTooComplex.ts, 34, 5)) +>getCtor : Symbol(getCtor, Decl(normalizedIntersectionTooComplex.ts, 30, 1)) +>all : Symbol(all, Decl(normalizedIntersectionTooComplex.ts, 33, 11)) + +const comp = ctor({ common: "ok", ref: x => console.log(x) }); +>comp : Symbol(comp, Decl(normalizedIntersectionTooComplex.ts, 35, 5)) +>ctor : Symbol(ctor, Decl(normalizedIntersectionTooComplex.ts, 34, 5)) +>common : Symbol(common, Decl(normalizedIntersectionTooComplex.ts, 35, 19)) +>ref : Symbol(ref, Decl(normalizedIntersectionTooComplex.ts, 35, 33)) +>x : Symbol(x, Decl(normalizedIntersectionTooComplex.ts, 35, 38)) +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>x : Symbol(x, Decl(normalizedIntersectionTooComplex.ts, 35, 38)) + diff --git a/tests/baselines/reference/normalizedIntersectionTooComplex.types b/tests/baselines/reference/normalizedIntersectionTooComplex.types new file mode 100644 index 00000000000..6750b0b0c73 --- /dev/null +++ b/tests/baselines/reference/normalizedIntersectionTooComplex.types @@ -0,0 +1,158 @@ +=== tests/cases/compiler/normalizedIntersectionTooComplex.ts === +// Repro from #30050 + +interface Obj { + ref: T; +>ref : T +} +interface Func { + (x: T): void; +>x : T +} +type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; +>UnionToIntersection : UnionToIntersection +>k : U +>k : I + +type CtorOf = (arg: UnionToIntersection) => T; +>CtorOf : CtorOf +>arg : UnionToIntersection + +interface Big { + "0": { common?: string; "0"?: number, ref?: Obj | Func; } +>"0" : { common?: string | undefined; "0"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"0" : number | undefined +>ref : Obj<{ common?: string | undefined; "0"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "0"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined + + "1": { common?: string; "1"?: number, ref?: Obj | Func; } +>"1" : { common?: string | undefined; "1"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"1" : number | undefined +>ref : Obj<{ common?: string | undefined; "1"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "1"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined + + "2": { common?: string; "2"?: number, ref?: Obj | Func; } +>"2" : { common?: string | undefined; "2"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"2" : number | undefined +>ref : Obj<{ common?: string | undefined; "2"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "2"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined + + "3": { common?: string; "3"?: number, ref?: Obj | Func; } +>"3" : { common?: string | undefined; "3"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"3" : number | undefined +>ref : Obj<{ common?: string | undefined; "3"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "3"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined + + "4": { common?: string; "4"?: number, ref?: Obj | Func; } +>"4" : { common?: string | undefined; "4"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"4" : number | undefined +>ref : Obj<{ common?: string | undefined; "4"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "4"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined + + "5": { common?: string; "5"?: number, ref?: Obj | Func; } +>"5" : { common?: string | undefined; "5"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"5" : number | undefined +>ref : Obj<{ common?: string | undefined; "5"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "5"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined + + "6": { common?: string; "6"?: number, ref?: Obj | Func; } +>"6" : { common?: string | undefined; "6"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"6" : number | undefined +>ref : Obj<{ common?: string | undefined; "6"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "6"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined + + "7": { common?: string; "7"?: number, ref?: Obj | Func; } +>"7" : { common?: string | undefined; "7"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"7" : number | undefined +>ref : Obj<{ common?: string | undefined; "7"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "7"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined + + "8": { common?: string; "8"?: number, ref?: Obj | Func; } +>"8" : { common?: string | undefined; "8"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"8" : number | undefined +>ref : Obj<{ common?: string | undefined; "8"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "8"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined + + "9": { common?: string; "9"?: number, ref?: Obj | Func; } +>"9" : { common?: string | undefined; "9"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"9" : number | undefined +>ref : Obj<{ common?: string | undefined; "9"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "9"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined + + "10": { common?: string; "10"?: number, ref?: Obj | Func; } +>"10" : { common?: string | undefined; "10"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"10" : number | undefined +>ref : Obj<{ common?: string | undefined; "10"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "10"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined + + "11": { common?: string; "11"?: number, ref?: Obj | Func; } +>"11" : { common?: string | undefined; "11"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"11" : number | undefined +>ref : Obj<{ common?: string | undefined; "11"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "11"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined + + "12": { common?: string; "12"?: number, ref?: Obj | Func; } +>"12" : { common?: string | undefined; "12"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"12" : number | undefined +>ref : Obj<{ common?: string | undefined; "12"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "12"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined + + "13": { common?: string; "13"?: number, ref?: Obj | Func; } +>"13" : { common?: string | undefined; "13"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"13" : number | undefined +>ref : Obj<{ common?: string | undefined; "13"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "13"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined + + "14": { common?: string; "14"?: number, ref?: Obj | Func; } +>"14" : { common?: string | undefined; "14"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"14" : number | undefined +>ref : Obj<{ common?: string | undefined; "14"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "14"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined + + "15": { common?: string; "15"?: number, ref?: Obj | Func; } +>"15" : { common?: string | undefined; "15"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"15" : number | undefined +>ref : Obj<{ common?: string | undefined; "15"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "15"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined + + "16": { common?: string; "16"?: number, ref?: Obj | Func; } +>"16" : { common?: string | undefined; "16"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"16" : number | undefined +>ref : Obj<{ common?: string | undefined; "16"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "16"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined + + "17": { common?: string; "17"?: number, ref?: Obj | Func; } +>"17" : { common?: string | undefined; "17"?: number | undefined; ref?: Obj | Func | undefined; } +>common : string | undefined +>"17" : number | undefined +>ref : Obj<{ common?: string | undefined; "17"?: number | undefined; ref?: Obj | Func | undefined; }> | Func<{ common?: string | undefined; "17"?: number | undefined; ref?: Obj | Func | undefined; }> | undefined +} +declare function getCtor(comp: T): CtorOf +>getCtor : (comp: T) => CtorOf +>comp : T + +declare var all: keyof Big; +>all : "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" + +const ctor = getCtor(all); +>ctor : CtorOf<{ common?: string | undefined; "0"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "1"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "2"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "3"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "4"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "5"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "6"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "7"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "8"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "9"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "10"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "11"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "12"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "13"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "14"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "15"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "16"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "17"?: number | undefined; ref?: Obj | Func | undefined; }> +>getCtor(all) : CtorOf<{ common?: string | undefined; "0"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "1"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "2"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "3"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "4"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "5"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "6"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "7"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "8"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "9"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "10"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "11"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "12"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "13"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "14"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "15"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "16"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "17"?: number | undefined; ref?: Obj | Func | undefined; }> +>getCtor : (comp: T) => CtorOf +>all : "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" + +const comp = ctor({ common: "ok", ref: x => console.log(x) }); +>comp : { common?: string | undefined; "0"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "1"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "2"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "3"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "4"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "5"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "6"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "7"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "8"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "9"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "10"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "11"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "12"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "13"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "14"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "15"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "16"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "17"?: number | undefined; ref?: Obj | Func | undefined; } +>ctor({ common: "ok", ref: x => console.log(x) }) : { common?: string | undefined; "0"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "1"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "2"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "3"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "4"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "5"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "6"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "7"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "8"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "9"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "10"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "11"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "12"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "13"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "14"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "15"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "16"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "17"?: number | undefined; ref?: Obj | Func | undefined; } +>ctor : CtorOf<{ common?: string | undefined; "0"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "1"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "2"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "3"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "4"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "5"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "6"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "7"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "8"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "9"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "10"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "11"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "12"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "13"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "14"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "15"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "16"?: number | undefined; ref?: Obj | Func | undefined; } | { common?: string | undefined; "17"?: number | undefined; ref?: Obj | Func | undefined; }> +>{ common: "ok", ref: x => console.log(x) } : { common: string; ref: (x: any) => void; } +>common : string +>"ok" : "ok" +>ref : (x: any) => void +>x => console.log(x) : (x: any) => void +>x : any +>console.log(x) : void +>console.log : (message?: any, ...optionalParams: any[]) => void +>console : Console +>log : (message?: any, ...optionalParams: any[]) => void +>x : any + diff --git a/tests/baselines/reference/objectSpreadIndexSignature.errors.txt b/tests/baselines/reference/objectSpreadIndexSignature.errors.txt index dede126d063..5c373b82ae4 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.errors.txt +++ b/tests/baselines/reference/objectSpreadIndexSignature.errors.txt @@ -1,4 +1,5 @@ -tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts(6,1): error TS7017: Element implicitly has an 'any' type because type '{ b: number; a: number; }' has no index signature. +tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts(6,1): error TS7053: Element implicitly has an 'any' type because expression of type '101' can't be used to index type '{ b: number; a: number; }'. + Property '101' does not exist on type '{ b: number; a: number; }'. ==== tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts (1 errors) ==== @@ -9,7 +10,8 @@ tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts(6,1): error T // only indexed has indexer, so i[101]: any i[101]; ~~~~~~ -!!! error TS7017: Element implicitly has an 'any' type because type '{ b: number; a: number; }' has no index signature. +!!! error TS7053: Element implicitly has an 'any' type because expression of type '101' can't be used to index type '{ b: number; a: number; }'. +!!! error TS7053: Property '101' does not exist on type '{ b: number; a: number; }'. let ii = { ...indexed1, ...indexed2 }; // both have indexer, so i[1001]: number | boolean ii[1001]; diff --git a/tests/baselines/reference/organizeImports/Unused_false_positive_module_augmentation.ts b/tests/baselines/reference/organizeImports/Unused_false_positive_module_augmentation.ts new file mode 100644 index 00000000000..4eaf184d493 --- /dev/null +++ b/tests/baselines/reference/organizeImports/Unused_false_positive_module_augmentation.ts @@ -0,0 +1,22 @@ +// ==ORIGINAL== + +import foo from 'foo'; +import { Caseless } from 'caseless'; + +declare module 'foo' {} +declare module 'caseless' { + interface Caseless { + test(name: KeyType): boolean; + } +} +// ==ORGANIZED== + +import 'caseless'; +import 'foo'; + +declare module 'foo' {} +declare module 'caseless' { + interface Caseless { + test(name: KeyType): boolean; + } +} \ No newline at end of file diff --git a/tests/baselines/reference/organizeImports/Unused_preserve_imports_for_module_augmentation_in_non_declaration_file.ts b/tests/baselines/reference/organizeImports/Unused_preserve_imports_for_module_augmentation_in_non_declaration_file.ts new file mode 100644 index 00000000000..6d28f89903a --- /dev/null +++ b/tests/baselines/reference/organizeImports/Unused_preserve_imports_for_module_augmentation_in_non_declaration_file.ts @@ -0,0 +1,22 @@ +// ==ORIGINAL== + +import foo from 'foo'; +import { Caseless } from 'caseless'; + +declare module 'foo' {} +declare module 'caseless' { + interface Caseless { + test(name: KeyType): boolean; + } +} +// ==ORGANIZED== + +import { Caseless } from 'caseless'; +import foo from 'foo'; + +declare module 'foo' {} +declare module 'caseless' { + interface Caseless { + test(name: KeyType): boolean; + } +} \ No newline at end of file diff --git a/tests/baselines/reference/propertyAccessStringIndexSignatureNoImplicitAny.errors.txt b/tests/baselines/reference/propertyAccessStringIndexSignatureNoImplicitAny.errors.txt index d5fda181096..0211bf321bf 100644 --- a/tests/baselines/reference/propertyAccessStringIndexSignatureNoImplicitAny.errors.txt +++ b/tests/baselines/reference/propertyAccessStringIndexSignatureNoImplicitAny.errors.txt @@ -1,5 +1,6 @@ tests/cases/conformance/expressions/propertyAccess/propertyAccessStringIndexSignatureNoImplicitAny.ts(10,7): error TS2339: Property 'nope' does not exist on type 'Empty'. -tests/cases/conformance/expressions/propertyAccess/propertyAccessStringIndexSignatureNoImplicitAny.ts(11,1): error TS7017: Element implicitly has an 'any' type because type 'Empty' has no index signature. +tests/cases/conformance/expressions/propertyAccess/propertyAccessStringIndexSignatureNoImplicitAny.ts(11,1): error TS7053: Element implicitly has an 'any' type because expression of type '"not allowed either"' can't be used to index type 'Empty'. + Property 'not allowed either' does not exist on type 'Empty'. ==== tests/cases/conformance/expressions/propertyAccess/propertyAccessStringIndexSignatureNoImplicitAny.ts (2 errors) ==== @@ -17,5 +18,6 @@ tests/cases/conformance/expressions/propertyAccess/propertyAccessStringIndexSign !!! error TS2339: Property 'nope' does not exist on type 'Empty'. empty["not allowed either"]; ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS7017: Element implicitly has an 'any' type because type 'Empty' has no index signature. +!!! error TS7053: Element implicitly has an 'any' type because expression of type '"not allowed either"' can't be used to index type 'Empty'. +!!! error TS7053: Property 'not allowed either' does not exist on type 'Empty'. \ No newline at end of file diff --git a/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM.js b/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM.js new file mode 100644 index 00000000000..c85d07ec99b --- /dev/null +++ b/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM.js @@ -0,0 +1,33 @@ +//// [reactTagNameComponentWithPropsNoOOM.tsx] +/// + +import * as React from "react"; +declare const Tag: keyof React.ReactHTML; + +const classes = ""; +const rest: {} = {}; +const children: any[] = []; + +{children} + + +//// [reactTagNameComponentWithPropsNoOOM.js] +"use strict"; +/// +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +exports.__esModule = true; +var React = require("react"); +var classes = ""; +var rest = {}; +var children = []; +React.createElement(Tag, __assign({ className: classes }, rest), children); diff --git a/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM.symbols b/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM.symbols new file mode 100644 index 00000000000..0b827bf7a0d --- /dev/null +++ b/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM.symbols @@ -0,0 +1,32 @@ +=== tests/cases/compiler/reactTagNameComponentWithPropsNoOOM.tsx === +/// + +import * as React from "react"; +>React : Symbol(React, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 2, 6)) + +declare const Tag: keyof React.ReactHTML; +>Tag : Symbol(Tag, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 3, 13)) +>React : Symbol(React, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 2, 6)) +>ReactHTML : Symbol(React.ReactHTML, Decl(react16.d.ts, 2089, 9)) + +const classes = ""; +>classes : Symbol(classes, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 5, 5)) + +const rest: {} = {}; +>rest : Symbol(rest, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 6, 5)) + +const children: any[] = []; +>children : Symbol(children, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 7, 5)) + + +>Tag : Symbol(Tag, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 3, 13)) +>className : Symbol(className, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 8, 4)) +>classes : Symbol(classes, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 5, 5)) +>rest : Symbol(rest, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 6, 5)) + +{children} +>children : Symbol(children, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 7, 5)) + + +>Tag : Symbol(Tag, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 3, 13)) + diff --git a/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM.types b/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM.types new file mode 100644 index 00000000000..f31716a55e4 --- /dev/null +++ b/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM.types @@ -0,0 +1,35 @@ +=== tests/cases/compiler/reactTagNameComponentWithPropsNoOOM.tsx === +/// + +import * as React from "react"; +>React : typeof React + +declare const Tag: keyof React.ReactHTML; +>Tag : "object" | "time" | "link" | "menu" | "dialog" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | "caption" | "cite" | "code" | "col" | "colgroup" | "data" | "datalist" | "dd" | "del" | "details" | "dfn" | "div" | "dl" | "dt" | "em" | "embed" | "fieldset" | "figcaption" | "figure" | "footer" | "form" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "head" | "header" | "hgroup" | "hr" | "html" | "i" | "iframe" | "img" | "input" | "ins" | "kbd" | "keygen" | "label" | "legend" | "li" | "main" | "map" | "mark" | "menuitem" | "meta" | "meter" | "nav" | "noscript" | "ol" | "optgroup" | "option" | "output" | "p" | "param" | "picture" | "pre" | "progress" | "q" | "rp" | "rt" | "ruby" | "s" | "samp" | "script" | "section" | "select" | "small" | "source" | "span" | "strong" | "style" | "sub" | "summary" | "sup" | "table" | "tbody" | "td" | "textarea" | "tfoot" | "th" | "thead" | "title" | "tr" | "track" | "u" | "ul" | "var" | "video" | "wbr" | "webview" +>React : any + +const classes = ""; +>classes : "" +>"" : "" + +const rest: {} = {}; +>rest : {} +>{} : {} + +const children: any[] = []; +>children : any[] +>[] : never[] + + +>{children} : JSX.Element +>Tag : "object" | "time" | "link" | "menu" | "dialog" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | "caption" | "cite" | "code" | "col" | "colgroup" | "data" | "datalist" | "dd" | "del" | "details" | "dfn" | "div" | "dl" | "dt" | "em" | "embed" | "fieldset" | "figcaption" | "figure" | "footer" | "form" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "head" | "header" | "hgroup" | "hr" | "html" | "i" | "iframe" | "img" | "input" | "ins" | "kbd" | "keygen" | "label" | "legend" | "li" | "main" | "map" | "mark" | "menuitem" | "meta" | "meter" | "nav" | "noscript" | "ol" | "optgroup" | "option" | "output" | "p" | "param" | "picture" | "pre" | "progress" | "q" | "rp" | "rt" | "ruby" | "s" | "samp" | "script" | "section" | "select" | "small" | "source" | "span" | "strong" | "style" | "sub" | "summary" | "sup" | "table" | "tbody" | "td" | "textarea" | "tfoot" | "th" | "thead" | "title" | "tr" | "track" | "u" | "ul" | "var" | "video" | "wbr" | "webview" +>className : string +>classes : "" +>rest : {} + +{children} +>children : any[] + + +>Tag : "object" | "time" | "link" | "menu" | "dialog" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | "caption" | "cite" | "code" | "col" | "colgroup" | "data" | "datalist" | "dd" | "del" | "details" | "dfn" | "div" | "dl" | "dt" | "em" | "embed" | "fieldset" | "figcaption" | "figure" | "footer" | "form" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "head" | "header" | "hgroup" | "hr" | "html" | "i" | "iframe" | "img" | "input" | "ins" | "kbd" | "keygen" | "label" | "legend" | "li" | "main" | "map" | "mark" | "menuitem" | "meta" | "meter" | "nav" | "noscript" | "ol" | "optgroup" | "option" | "output" | "p" | "param" | "picture" | "pre" | "progress" | "q" | "rp" | "rt" | "ruby" | "s" | "samp" | "script" | "section" | "select" | "small" | "source" | "span" | "strong" | "style" | "sub" | "summary" | "sup" | "table" | "tbody" | "td" | "textarea" | "tfoot" | "th" | "thead" | "title" | "tr" | "track" | "u" | "ul" | "var" | "video" | "wbr" | "webview" + diff --git a/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM2.js b/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM2.js new file mode 100644 index 00000000000..4b6e9d0c54a --- /dev/null +++ b/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM2.js @@ -0,0 +1,33 @@ +//// [reactTagNameComponentWithPropsNoOOM2.tsx] +/// + +import * as React from "react"; +declare const Tag: keyof React.ReactHTML; + +const classes = ""; +const rest: React.HTMLAttributes = {}; +const children: any[] = []; + +{children} + + +//// [reactTagNameComponentWithPropsNoOOM2.js] +"use strict"; +/// +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +exports.__esModule = true; +var React = require("react"); +var classes = ""; +var rest = {}; +var children = []; +React.createElement(Tag, __assign({ className: classes }, rest), children); diff --git a/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM2.symbols b/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM2.symbols new file mode 100644 index 00000000000..658f9fd5c43 --- /dev/null +++ b/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM2.symbols @@ -0,0 +1,35 @@ +=== tests/cases/compiler/reactTagNameComponentWithPropsNoOOM2.tsx === +/// + +import * as React from "react"; +>React : Symbol(React, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 2, 6)) + +declare const Tag: keyof React.ReactHTML; +>Tag : Symbol(Tag, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 3, 13)) +>React : Symbol(React, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 2, 6)) +>ReactHTML : Symbol(React.ReactHTML, Decl(react16.d.ts, 2089, 9)) + +const classes = ""; +>classes : Symbol(classes, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 5, 5)) + +const rest: React.HTMLAttributes = {}; +>rest : Symbol(rest, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 6, 5)) +>React : Symbol(React, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 2, 6)) +>HTMLAttributes : Symbol(React.HTMLAttributes, Decl(react16.d.ts, 1048, 9), Decl(react16.d.ts, 1105, 9)) +>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + +const children: any[] = []; +>children : Symbol(children, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 7, 5)) + + +>Tag : Symbol(Tag, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 3, 13)) +>className : Symbol(className, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 8, 4)) +>classes : Symbol(classes, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 5, 5)) +>rest : Symbol(rest, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 6, 5)) + +{children} +>children : Symbol(children, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 7, 5)) + + +>Tag : Symbol(Tag, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 3, 13)) + diff --git a/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM2.types b/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM2.types new file mode 100644 index 00000000000..fac8a844e03 --- /dev/null +++ b/tests/baselines/reference/reactTagNameComponentWithPropsNoOOM2.types @@ -0,0 +1,36 @@ +=== tests/cases/compiler/reactTagNameComponentWithPropsNoOOM2.tsx === +/// + +import * as React from "react"; +>React : typeof React + +declare const Tag: keyof React.ReactHTML; +>Tag : "object" | "time" | "link" | "menu" | "dialog" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | "caption" | "cite" | "code" | "col" | "colgroup" | "data" | "datalist" | "dd" | "del" | "details" | "dfn" | "div" | "dl" | "dt" | "em" | "embed" | "fieldset" | "figcaption" | "figure" | "footer" | "form" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "head" | "header" | "hgroup" | "hr" | "html" | "i" | "iframe" | "img" | "input" | "ins" | "kbd" | "keygen" | "label" | "legend" | "li" | "main" | "map" | "mark" | "menuitem" | "meta" | "meter" | "nav" | "noscript" | "ol" | "optgroup" | "option" | "output" | "p" | "param" | "picture" | "pre" | "progress" | "q" | "rp" | "rt" | "ruby" | "s" | "samp" | "script" | "section" | "select" | "small" | "source" | "span" | "strong" | "style" | "sub" | "summary" | "sup" | "table" | "tbody" | "td" | "textarea" | "tfoot" | "th" | "thead" | "title" | "tr" | "track" | "u" | "ul" | "var" | "video" | "wbr" | "webview" +>React : any + +const classes = ""; +>classes : "" +>"" : "" + +const rest: React.HTMLAttributes = {}; +>rest : React.HTMLAttributes +>React : any +>{} : {} + +const children: any[] = []; +>children : any[] +>[] : never[] + + +>{children} : JSX.Element +>Tag : "object" | "time" | "link" | "menu" | "dialog" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | "caption" | "cite" | "code" | "col" | "colgroup" | "data" | "datalist" | "dd" | "del" | "details" | "dfn" | "div" | "dl" | "dt" | "em" | "embed" | "fieldset" | "figcaption" | "figure" | "footer" | "form" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "head" | "header" | "hgroup" | "hr" | "html" | "i" | "iframe" | "img" | "input" | "ins" | "kbd" | "keygen" | "label" | "legend" | "li" | "main" | "map" | "mark" | "menuitem" | "meta" | "meter" | "nav" | "noscript" | "ol" | "optgroup" | "option" | "output" | "p" | "param" | "picture" | "pre" | "progress" | "q" | "rp" | "rt" | "ruby" | "s" | "samp" | "script" | "section" | "select" | "small" | "source" | "span" | "strong" | "style" | "sub" | "summary" | "sup" | "table" | "tbody" | "td" | "textarea" | "tfoot" | "th" | "thead" | "title" | "tr" | "track" | "u" | "ul" | "var" | "video" | "wbr" | "webview" +>className : string +>classes : "" +>rest : React.HTMLAttributes + +{children} +>children : any[] + + +>Tag : "object" | "time" | "link" | "menu" | "dialog" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | "caption" | "cite" | "code" | "col" | "colgroup" | "data" | "datalist" | "dd" | "del" | "details" | "dfn" | "div" | "dl" | "dt" | "em" | "embed" | "fieldset" | "figcaption" | "figure" | "footer" | "form" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "head" | "header" | "hgroup" | "hr" | "html" | "i" | "iframe" | "img" | "input" | "ins" | "kbd" | "keygen" | "label" | "legend" | "li" | "main" | "map" | "mark" | "menuitem" | "meta" | "meter" | "nav" | "noscript" | "ol" | "optgroup" | "option" | "output" | "p" | "param" | "picture" | "pre" | "progress" | "q" | "rp" | "rt" | "ruby" | "s" | "samp" | "script" | "section" | "select" | "small" | "source" | "span" | "strong" | "style" | "sub" | "summary" | "sup" | "table" | "tbody" | "td" | "textarea" | "tfoot" | "th" | "thead" | "title" | "tr" | "track" | "u" | "ul" | "var" | "video" | "wbr" | "webview" + diff --git a/tests/baselines/reference/systemModuleTargetES6.js b/tests/baselines/reference/systemModuleTargetES6.js index 943e57ff742..0df2835683e 100644 --- a/tests/baselines/reference/systemModuleTargetES6.js +++ b/tests/baselines/reference/systemModuleTargetES6.js @@ -35,8 +35,8 @@ System.register([], function (exports_1, context_1) { MyClass2 = class MyClass2 { static getInstance() { return MyClass2.value; } }; - MyClass2.value = 42; exports_1("MyClass2", MyClass2); + MyClass2.value = 42; } }; }); diff --git a/tests/baselines/reference/typeFromPrototypeAssignment3.errors.txt b/tests/baselines/reference/typeFromPrototypeAssignment3.errors.txt index 579c3efac72..02ff4ae344c 100644 --- a/tests/baselines/reference/typeFromPrototypeAssignment3.errors.txt +++ b/tests/baselines/reference/typeFromPrototypeAssignment3.errors.txt @@ -1,5 +1,6 @@ tests/cases/conformance/salsa/bug26885.js(2,5): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. -tests/cases/conformance/salsa/bug26885.js(11,16): error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. +tests/cases/conformance/salsa/bug26885.js(11,16): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'. + No index signature with a parameter of type 'string' was found on type '{}'. ==== tests/cases/conformance/salsa/bug26885.js (2 errors) ==== @@ -17,7 +18,8 @@ tests/cases/conformance/salsa/bug26885.js(11,16): error TS7017: Element implicit get(key) { return this._map[key + '']; ~~~~~~~~~~~~~~~~~~~ -!!! error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. +!!! error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'. +!!! error TS7053: No index signature with a parameter of type 'string' was found on type '{}'. } } diff --git a/tests/baselines/reference/typesVersions.emptyTypes.js b/tests/baselines/reference/typesVersions.emptyTypes.js new file mode 100644 index 00000000000..0bcc27d7a65 --- /dev/null +++ b/tests/baselines/reference/typesVersions.emptyTypes.js @@ -0,0 +1,20 @@ +//// [tests/cases/conformance/moduleResolution/typesVersions.emptyTypes.ts] //// + +//// [package.json] +{ + "types": "", + "typesVersions": { + ">=3.1.0-0": { "*" : ["ts3.1/*"] } + } +} + +//// [index.d.ts] +export const a = 0; + +//// [user.ts] +import { a } from "a"; + + +//// [user.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/tests/baselines/reference/typesVersions.emptyTypes.symbols b/tests/baselines/reference/typesVersions.emptyTypes.symbols new file mode 100644 index 00000000000..a4441e407d7 --- /dev/null +++ b/tests/baselines/reference/typesVersions.emptyTypes.symbols @@ -0,0 +1,8 @@ +=== /a/ts3.1/index.d.ts === +export const a = 0; +>a : Symbol(a, Decl(index.d.ts, 0, 12)) + +=== /b/user.ts === +import { a } from "a"; +>a : Symbol(a, Decl(user.ts, 0, 8)) + diff --git a/tests/baselines/reference/typesVersions.emptyTypes.trace.json b/tests/baselines/reference/typesVersions.emptyTypes.trace.json new file mode 100644 index 00000000000..e7a9e7547cf --- /dev/null +++ b/tests/baselines/reference/typesVersions.emptyTypes.trace.json @@ -0,0 +1,24 @@ +[ + "======== Resolving module 'a' from '/b/user.ts'. ========", + "Module resolution kind is not specified, using 'NodeJs'.", + "'baseUrl' option is set to '/', using this value to resolve non-relative module name 'a'.", + "Resolving module name 'a' relative to base url '/' - '/a'.", + "Loading module as file / folder, candidate module location '/a', target file type 'TypeScript'.", + "File '/a.ts' does not exist.", + "File '/a.tsx' does not exist.", + "File '/a.d.ts' does not exist.", + "Found 'package.json' at '/a/package.json'.", + "'package.json' has a 'typesVersions' field with version-specific path mappings.", + "'package.json' does not have a 'typings' field.", + "'package.json' had a falsy 'types' field.", + "'package.json' does not have a 'main' field.", + "'package.json' has a 'typesVersions' entry '>=3.1.0-0' that matches compiler version '3.1.0-dev', looking for a pattern to match module name 'index'.", + "Module name 'index', matched pattern '*'.", + "Trying substitution 'ts3.1/*', candidate module location: 'ts3.1/index'.", + "File '/a/ts3.1/index' does not exist.", + "Loading module as file / folder, candidate module location '/a/ts3.1/index', target file type 'TypeScript'.", + "File '/a/ts3.1/index.ts' does not exist.", + "File '/a/ts3.1/index.tsx' does not exist.", + "File '/a/ts3.1/index.d.ts' exist - use it as a name resolution result.", + "======== Module name 'a' was successfully resolved to '/a/ts3.1/index.d.ts'. ========" +] \ No newline at end of file diff --git a/tests/baselines/reference/typesVersions.emptyTypes.types b/tests/baselines/reference/typesVersions.emptyTypes.types new file mode 100644 index 00000000000..578d4695e1c --- /dev/null +++ b/tests/baselines/reference/typesVersions.emptyTypes.types @@ -0,0 +1,9 @@ +=== /a/ts3.1/index.d.ts === +export const a = 0; +>a : 0 +>0 : 0 + +=== /b/user.ts === +import { a } from "a"; +>a : 0 + diff --git a/tests/baselines/reference/unionTypeCallSignatures5.js b/tests/baselines/reference/unionTypeCallSignatures5.js new file mode 100644 index 00000000000..2e756540d94 --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures5.js @@ -0,0 +1,17 @@ +//// [unionTypeCallSignatures5.ts] +// #31485 +interface A { + (this: void, b?: number): void; +} +interface B { + (this: number, b?: number): void; +} +interface C { + (i: number): void; +} +declare const fn: A | B | C; +fn(0); + + +//// [unionTypeCallSignatures5.js] +fn(0); diff --git a/tests/baselines/reference/unionTypeCallSignatures5.symbols b/tests/baselines/reference/unionTypeCallSignatures5.symbols new file mode 100644 index 00000000000..d729dcd7aba --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures5.symbols @@ -0,0 +1,31 @@ +=== tests/cases/conformance/types/union/unionTypeCallSignatures5.ts === +// #31485 +interface A { +>A : Symbol(A, Decl(unionTypeCallSignatures5.ts, 0, 0)) + + (this: void, b?: number): void; +>this : Symbol(this, Decl(unionTypeCallSignatures5.ts, 2, 3)) +>b : Symbol(b, Decl(unionTypeCallSignatures5.ts, 2, 14)) +} +interface B { +>B : Symbol(B, Decl(unionTypeCallSignatures5.ts, 3, 1)) + + (this: number, b?: number): void; +>this : Symbol(this, Decl(unionTypeCallSignatures5.ts, 5, 3)) +>b : Symbol(b, Decl(unionTypeCallSignatures5.ts, 5, 16)) +} +interface C { +>C : Symbol(C, Decl(unionTypeCallSignatures5.ts, 6, 1)) + + (i: number): void; +>i : Symbol(i, Decl(unionTypeCallSignatures5.ts, 8, 3)) +} +declare const fn: A | B | C; +>fn : Symbol(fn, Decl(unionTypeCallSignatures5.ts, 10, 13)) +>A : Symbol(A, Decl(unionTypeCallSignatures5.ts, 0, 0)) +>B : Symbol(B, Decl(unionTypeCallSignatures5.ts, 3, 1)) +>C : Symbol(C, Decl(unionTypeCallSignatures5.ts, 6, 1)) + +fn(0); +>fn : Symbol(fn, Decl(unionTypeCallSignatures5.ts, 10, 13)) + diff --git a/tests/baselines/reference/unionTypeCallSignatures5.types b/tests/baselines/reference/unionTypeCallSignatures5.types new file mode 100644 index 00000000000..53ce4ea6550 --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures5.types @@ -0,0 +1,24 @@ +=== tests/cases/conformance/types/union/unionTypeCallSignatures5.ts === +// #31485 +interface A { + (this: void, b?: number): void; +>this : void +>b : number +} +interface B { + (this: number, b?: number): void; +>this : number +>b : number +} +interface C { + (i: number): void; +>i : number +} +declare const fn: A | B | C; +>fn : A | B | C + +fn(0); +>fn(0) : void +>fn : A | B | C +>0 : 0 + diff --git a/tests/baselines/reference/unionTypeWithIndexSignature.errors.txt b/tests/baselines/reference/unionTypeWithIndexSignature.errors.txt index fb4463bc2d9..14a3ffc58a6 100644 --- a/tests/baselines/reference/unionTypeWithIndexSignature.errors.txt +++ b/tests/baselines/reference/unionTypeWithIndexSignature.errors.txt @@ -1,9 +1,11 @@ tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(11,3): error TS2339: Property 'bar' does not exist on type 'Missing'. Property 'bar' does not exist on type '{ [s: string]: string; }'. tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(14,4): error TS2540: Cannot assign to 'foo' because it is a read-only property. -tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(24,1): error TS7017: Element implicitly has an 'any' type because type 'Both' has no index signature. +tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(24,1): error TS7053: Element implicitly has an 'any' type because expression of type '1' can't be used to index type 'Both'. + Property '1' does not exist on type 'Both'. tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(25,1): error TS2322: Type '"not ok"' is not assignable to type 'number'. -tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(26,1): error TS7017: Element implicitly has an 'any' type because type 'Both' has no index signature. +tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(26,1): error TS7053: Element implicitly has an 'any' type because expression of type 'unique symbol' can't be used to index type 'Both'. + Property '[sym]' does not exist on type 'Both'. ==== tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts (5 errors) ==== @@ -37,11 +39,13 @@ tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(26,1): error both[0] = 1 both[1] = 0 // not ok ~~~~~~~ -!!! error TS7017: Element implicitly has an 'any' type because type 'Both' has no index signature. +!!! error TS7053: Element implicitly has an 'any' type because expression of type '1' can't be used to index type 'Both'. +!!! error TS7053: Property '1' does not exist on type 'Both'. both[0] = 'not ok' ~~~~~~~ !!! error TS2322: Type '"not ok"' is not assignable to type 'number'. both[sym] = 'not ok' ~~~~~~~~~ -!!! error TS7017: Element implicitly has an 'any' type because type 'Both' has no index signature. +!!! error TS7053: Element implicitly has an 'any' type because expression of type 'unique symbol' can't be used to index type 'Both'. +!!! error TS7053: Property '[sym]' does not exist on type 'Both'. \ No newline at end of file diff --git a/tests/baselines/reference/useObjectValuesAndEntries1.types b/tests/baselines/reference/useObjectValuesAndEntries1.types index 94deebdfd8c..bbfd4c87d2a 100644 --- a/tests/baselines/reference/useObjectValuesAndEntries1.types +++ b/tests/baselines/reference/useObjectValuesAndEntries1.types @@ -121,16 +121,16 @@ enum E { A, B } >B : E.B var entries5 = Object.entries(E); // [string, any][] ->entries5 : [string, any][] ->Object.entries(E) : [string, any][] +>entries5 : [string, string | E][] +>Object.entries(E) : [string, string | E][] >Object.entries : { (o: { [s: string]: T; } | ArrayLike): [string, T][]; (o: {}): [string, any][]; } >Object : ObjectConstructor >entries : { (o: { [s: string]: T; } | ArrayLike): [string, T][]; (o: {}): [string, any][]; } >E : typeof E var values5 = Object.values(E); // any[] ->values5 : any[] ->Object.values(E) : any[] +>values5 : (string | E)[] +>Object.values(E) : (string | E)[] >Object.values : { (o: { [s: string]: T; } | ArrayLike): T[]; (o: {}): any[]; } >Object : ObjectConstructor >values : { (o: { [s: string]: T; } | ArrayLike): T[]; (o: {}): any[]; } diff --git a/tests/baselines/reference/user/bluebird.log b/tests/baselines/reference/user/bluebird.log index 5c1689ff49b..26d7270bcb6 100644 --- a/tests/baselines/reference/user/bluebird.log +++ b/tests/baselines/reference/user/bluebird.log @@ -131,60 +131,62 @@ node_modules/bluebird/js/release/promise.js(65,15): error TS2350: Only a void fu node_modules/bluebird/js/release/promise.js(65,68): error TS2339: Property 'classString' does not exist on type 'typeof ret'. node_modules/bluebird/js/release/promise.js(95,22): error TS2339: Property 'isObject' does not exist on type 'typeof ret'. node_modules/bluebird/js/release/promise.js(99,59): error TS2339: Property 'classString' does not exist on type 'typeof ret'. -node_modules/bluebird/js/release/promise.js(119,22): error TS2339: Property 'classString' does not exist on type 'typeof ret'. -node_modules/bluebird/js/release/promise.js(121,32): error TS2339: Property 'classString' does not exist on type 'typeof ret'. -node_modules/bluebird/js/release/promise.js(123,14): error TS2339: Property '_warn' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(136,68): error TS2339: Property 'classString' does not exist on type 'typeof ret'. -node_modules/bluebird/js/release/promise.js(148,14): error TS2551: Property 'isFulfilled' does not exist on type 'Promise'. Did you mean '_setFulfilled'? -node_modules/bluebird/js/release/promise.js(149,37): error TS2339: Property 'value' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(151,21): error TS2551: Property 'isRejected' does not exist on type 'Promise'. Did you mean '_setRejected'? -node_modules/bluebird/js/release/promise.js(152,36): error TS2339: Property 'reason' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(160,14): error TS2339: Property '_warn' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(166,29): error TS2339: Property 'originatesFromRejection' does not exist on type 'typeof ret'. -node_modules/bluebird/js/release/promise.js(177,9): error TS2339: Property '_captureStackTrace' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(207,9): error TS2339: Property '_captureStackTrace' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(214,15): error TS2350: Only a void function can be called with the 'new' keyword. -node_modules/bluebird/js/release/promise.js(214,68): error TS2339: Property 'classString' does not exist on type 'typeof ret'. -node_modules/bluebird/js/release/promise.js(238,63): error TS2339: Property '_boundTo' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(241,14): error TS2339: Property '_fireEvent' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(253,20): error TS2339: Property '_unsetRejectionIsUnhandled' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(257,20): error TS2339: Property '_attachExtraTrace' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(264,26): error TS2339: Property 'domainBind' does not exist on type 'typeof ret'. -node_modules/bluebird/js/release/promise.js(295,10): error TS2339: Property '_fireEvent' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(106,19): error TS2350: Only a void function can be called with the 'new' keyword. +node_modules/bluebird/js/release/promise.js(107,60): error TS2554: Expected 0 arguments, but got 1. +node_modules/bluebird/js/release/promise.js(124,22): error TS2339: Property 'classString' does not exist on type 'typeof ret'. +node_modules/bluebird/js/release/promise.js(126,32): error TS2339: Property 'classString' does not exist on type 'typeof ret'. +node_modules/bluebird/js/release/promise.js(128,14): error TS2339: Property '_warn' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(141,68): error TS2339: Property 'classString' does not exist on type 'typeof ret'. +node_modules/bluebird/js/release/promise.js(153,14): error TS2551: Property 'isFulfilled' does not exist on type 'Promise'. Did you mean '_setFulfilled'? +node_modules/bluebird/js/release/promise.js(154,37): error TS2339: Property 'value' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(156,21): error TS2551: Property 'isRejected' does not exist on type 'Promise'. Did you mean '_setRejected'? +node_modules/bluebird/js/release/promise.js(157,36): error TS2339: Property 'reason' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(165,14): error TS2339: Property '_warn' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(171,29): error TS2339: Property 'originatesFromRejection' does not exist on type 'typeof ret'. +node_modules/bluebird/js/release/promise.js(182,9): error TS2339: Property '_captureStackTrace' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(212,9): error TS2339: Property '_captureStackTrace' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(219,15): error TS2350: Only a void function can be called with the 'new' keyword. +node_modules/bluebird/js/release/promise.js(219,68): error TS2339: Property 'classString' does not exist on type 'typeof ret'. +node_modules/bluebird/js/release/promise.js(243,63): error TS2339: Property '_boundTo' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(246,14): error TS2339: Property '_fireEvent' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(258,20): error TS2339: Property '_unsetRejectionIsUnhandled' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(262,20): error TS2339: Property '_attachExtraTrace' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(269,26): error TS2339: Property 'domainBind' does not exist on type 'typeof ret'. node_modules/bluebird/js/release/promise.js(300,10): error TS2339: Property '_fireEvent' does not exist on type 'Promise'. node_modules/bluebird/js/release/promise.js(305,10): error TS2339: Property '_fireEvent' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(322,10): error TS2339: Property '_fireEvent' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(339,42): error TS2339: Property '_isBound' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(400,50): error TS2339: Property 'domainBind' does not exist on type 'typeof ret'. -node_modules/bluebird/js/release/promise.js(404,49): error TS2339: Property 'domainBind' does not exist on type 'typeof ret'. -node_modules/bluebird/js/release/promise.js(412,50): error TS2339: Property 'domainBind' does not exist on type 'typeof ret'. -node_modules/bluebird/js/release/promise.js(416,49): error TS2339: Property 'domainBind' does not exist on type 'typeof ret'. -node_modules/bluebird/js/release/promise.js(434,26): error TS2339: Property '_propagateFrom' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(454,31): error TS2339: Property '_value' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(456,30): error TS2339: Property '_reason' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(459,17): error TS2339: Property '_attachExtraTrace' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(466,22): error TS2339: Property 'ensureErrorObject' does not exist on type 'typeof ret'. -node_modules/bluebird/js/release/promise.js(470,18): error TS2339: Property 'classString' does not exist on type 'typeof ret'. -node_modules/bluebird/js/release/promise.js(471,14): error TS2339: Property '_warn' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(473,10): error TS2339: Property '_attachExtraTrace' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(480,10): error TS2339: Property '_captureStackTrace' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(481,10): error TS2339: Property '_pushContext' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(483,18): error TS2339: Property '_execute' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(489,10): error TS2339: Property '_popContext' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(506,19): error TS2350: Only a void function can be called with the 'new' keyword. -node_modules/bluebird/js/release/promise.js(507,42): error TS2339: Property 'classString' does not exist on type 'typeof ret'. -node_modules/bluebird/js/release/promise.js(558,22): error TS2339: Property '_promiseCancelled' does not exist on type '{}'. -node_modules/bluebird/js/release/promise.js(572,23): error TS2339: Property '_isResolved' does not exist on type '{}'. -node_modules/bluebird/js/release/promise.js(574,26): error TS2339: Property '_promiseFulfilled' does not exist on type '{}'. -node_modules/bluebird/js/release/promise.js(576,26): error TS2339: Property '_promiseRejected' does not exist on type '{}'. -node_modules/bluebird/js/release/promise.js(630,14): error TS2339: Property '_attachExtraTrace' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(642,14): error TS2339: Property '_dereferenceTrace' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(653,46): error TS2339: Property 'isNode' does not exist on type 'typeof ret'. -node_modules/bluebird/js/release/promise.js(659,14): error TS2339: Property '_ensurePossibleRejectionHandled' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(699,10): error TS2339: Property '_clearCancellationData' does not exist on type 'Promise'. -node_modules/bluebird/js/release/promise.js(724,6): error TS2339: Property 'notEnumerableProp' does not exist on type 'typeof ret'. -node_modules/bluebird/js/release/promise.js(754,10): error TS2339: Property 'toFastProperties' does not exist on type 'typeof ret'. -node_modules/bluebird/js/release/promise.js(755,10): error TS2339: Property 'toFastProperties' does not exist on type 'typeof ret'. +node_modules/bluebird/js/release/promise.js(310,10): error TS2339: Property '_fireEvent' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(327,10): error TS2339: Property '_fireEvent' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(344,42): error TS2339: Property '_isBound' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(405,50): error TS2339: Property 'domainBind' does not exist on type 'typeof ret'. +node_modules/bluebird/js/release/promise.js(409,49): error TS2339: Property 'domainBind' does not exist on type 'typeof ret'. +node_modules/bluebird/js/release/promise.js(417,50): error TS2339: Property 'domainBind' does not exist on type 'typeof ret'. +node_modules/bluebird/js/release/promise.js(421,49): error TS2339: Property 'domainBind' does not exist on type 'typeof ret'. +node_modules/bluebird/js/release/promise.js(439,26): error TS2339: Property '_propagateFrom' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(459,31): error TS2339: Property '_value' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(461,30): error TS2339: Property '_reason' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(464,17): error TS2339: Property '_attachExtraTrace' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(471,22): error TS2339: Property 'ensureErrorObject' does not exist on type 'typeof ret'. +node_modules/bluebird/js/release/promise.js(475,18): error TS2339: Property 'classString' does not exist on type 'typeof ret'. +node_modules/bluebird/js/release/promise.js(476,14): error TS2339: Property '_warn' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(478,10): error TS2339: Property '_attachExtraTrace' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(485,10): error TS2339: Property '_captureStackTrace' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(486,10): error TS2339: Property '_pushContext' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(488,18): error TS2339: Property '_execute' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(494,10): error TS2339: Property '_popContext' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(511,19): error TS2350: Only a void function can be called with the 'new' keyword. +node_modules/bluebird/js/release/promise.js(512,42): error TS2339: Property 'classString' does not exist on type 'typeof ret'. +node_modules/bluebird/js/release/promise.js(563,22): error TS2339: Property '_promiseCancelled' does not exist on type '{}'. +node_modules/bluebird/js/release/promise.js(577,23): error TS2339: Property '_isResolved' does not exist on type '{}'. +node_modules/bluebird/js/release/promise.js(579,26): error TS2339: Property '_promiseFulfilled' does not exist on type '{}'. +node_modules/bluebird/js/release/promise.js(581,26): error TS2339: Property '_promiseRejected' does not exist on type '{}'. +node_modules/bluebird/js/release/promise.js(635,14): error TS2339: Property '_attachExtraTrace' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(647,14): error TS2339: Property '_dereferenceTrace' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(658,46): error TS2339: Property 'isNode' does not exist on type 'typeof ret'. +node_modules/bluebird/js/release/promise.js(664,14): error TS2339: Property '_ensurePossibleRejectionHandled' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(704,10): error TS2339: Property '_clearCancellationData' does not exist on type 'Promise'. +node_modules/bluebird/js/release/promise.js(737,6): error TS2339: Property 'notEnumerableProp' does not exist on type 'typeof ret'. +node_modules/bluebird/js/release/promise.js(767,10): error TS2339: Property 'toFastProperties' does not exist on type 'typeof ret'. +node_modules/bluebird/js/release/promise.js(768,10): error TS2339: Property 'toFastProperties' does not exist on type 'typeof ret'. node_modules/bluebird/js/release/promise_array.js(5,20): error TS2339: Property 'isArray' does not exist on type 'typeof ret'. node_modules/bluebird/js/release/promise_array.js(26,6): error TS2339: Property 'inherits' does not exist on type 'typeof ret'. node_modules/bluebird/js/release/promise_array.js(61,19): error TS2339: Property 'asArray' does not exist on type 'typeof ret'. diff --git a/tests/baselines/reference/user/chrome-devtools-frontend.log b/tests/baselines/reference/user/chrome-devtools-frontend.log index bdde6b918c0..7c51aef5159 100644 --- a/tests/baselines/reference/user/chrome-devtools-frontend.log +++ b/tests/baselines/reference/user/chrome-devtools-frontend.log @@ -698,13 +698,6 @@ node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighth node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(10092,16): error TS2304: Cannot find name 'd41d8cd98f00b204e9800998ecf8427e_LibraryDetectorTests'. node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(10513,19): error TS2488: Type 'NodeListOf' must have a '[Symbol.iterator]()' method that returns an iterator. node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(10811,19): error TS2304: Cannot find name 'getElementsInDocument'. -node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(11441,1): error TS2322: Type 'unknown' is not assignable to type 'number'. -node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(11444,1): error TS2322: Type 'unknown' is not assignable to type 'number'. -node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(11447,15): error TS2339: Property 'textLength' does not exist on type 'unknown'. -node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(11447,28): error TS2339: Property 'textLength' does not exist on type 'unknown'. -node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(11450,43): error TS2339: Property 'node' does not exist on type 'unknown'. -node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(11453,6): error TS2339: Property 'cssRule' does not exist on type 'unknown'. -node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(11460,6): error TS2339: Property 'cssRule' does not exist on type 'unknown'. node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(12197,34): error TS2554: Expected 0 arguments, but got 2. node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(12327,36): error TS2554: Expected 0 arguments, but got 1. node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(13607,7): error TS2339: Property 'protocolMethod' does not exist on type 'Error'. @@ -3019,7 +3012,15 @@ node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighth node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(65285,7): error TS2339: Property 'description' does not exist on type 'Error'. node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(65310,1): error TS2323: Cannot redeclare exported variable '__esModule'. node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(65379,1): error TS2323: Cannot redeclare exported variable '__esModule'. +node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(65443,1): error TS2322: Type '{ line: number; column: number; }' is not assignable to type '{}'. + Property 'line' does not exist on type '{}'. +node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(65464,1): error TS2322: Type '{ line: number; column: number; }' is not assignable to type '{}'. + Property 'line' does not exist on type '{}'. node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(65468,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'entry' must be of type '{ multiLine: boolean; slice: any[]; range: number[]; loc: { start: { line: number; column: number; }; end: {}; }; }', but here has type '{ multiLine: boolean; slice: any[]; range: any[]; loc: { start: { line: number; column: number; }; end: {}; }; }'. +node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(65507,1): error TS2322: Type '{ line: number; column: number; }' is not assignable to type '{}'. + Property 'line' does not exist on type '{}'. +node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(65529,1): error TS2322: Type '{ line: number; column: number; }' is not assignable to type '{}'. + Property 'line' does not exist on type '{}'. node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(65533,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'entry' must be of type '{ multiLine: boolean; slice: number[]; range: any[]; loc: { start: { line: number; column: number; }; end: {}; }; }', but here has type '{ multiLine: boolean; slice: any[]; range: any[]; loc: { start: { line: number; column: number; }; end: {}; }; }'. node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(65576,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'comment' must be of type '{ multiLine: boolean; slice: any[]; range: number[]; loc: { start: { line: number; column: number; }; end: {}; }; }[]', but here has type '{ multiLine: boolean; slice: number[]; range: any[]; loc: { start: { line: number; column: number; }; end: {}; }; }[]'. node_modules/chrome-devtools-frontend/front_end/audits2_worker/lighthouse/lighthouse-background.js(66529,1): error TS2323: Cannot redeclare exported variable '__esModule'. @@ -3129,9 +3130,6 @@ node_modules/chrome-devtools-frontend/front_end/bindings/BreakpointManager.js(53 node_modules/chrome-devtools-frontend/front_end/bindings/BreakpointManager.js(655,51): error TS2339: Property 'valuesArray' does not exist on type 'Map'. node_modules/chrome-devtools-frontend/front_end/bindings/BreakpointManager.js(667,51): error TS2339: Property 'valuesArray' does not exist on type 'Map'. node_modules/chrome-devtools-frontend/front_end/bindings/BreakpointManager.js(674,79): error TS2345: Argument of type 'this' is not assignable to parameter of type '{ modelAdded(model: T): void; modelRemoved(model: T): void; }'. - Type 'Breakpoint' is not assignable to type '{ modelAdded(model: T): void; modelRemoved(model: T): void; }'. - Types of property 'modelAdded' are incompatible. - Type '(debuggerModel: DebuggerModel) => void' is not assignable to type '(model: T) => void'. node_modules/chrome-devtools-frontend/front_end/bindings/BreakpointManager.js(713,51): error TS2339: Property 'valuesArray' does not exist on type 'Map'. node_modules/chrome-devtools-frontend/front_end/bindings/BreakpointManager.js(787,14): error TS7014: Function type, which lacks return-type annotation, implicitly has an 'any' return type. node_modules/chrome-devtools-frontend/front_end/bindings/BreakpointManager.js(862,14): error TS7014: Function type, which lacks return-type annotation, implicitly has an 'any' return type. @@ -3389,7 +3387,7 @@ node_modules/chrome-devtools-frontend/front_end/cm/codemirror.js(2765,22): error node_modules/chrome-devtools-frontend/front_end/cm/codemirror.js(2785,91): error TS2339: Property 'xRel' does not exist on type 'Pos'. node_modules/chrome-devtools-frontend/front_end/cm/codemirror.js(2855,32): error TS2339: Property 'left' does not exist on type 'never'. node_modules/chrome-devtools-frontend/front_end/cm/codemirror.js(2855,49): error TS2339: Property 'right' does not exist on type 'never'. -node_modules/chrome-devtools-frontend/front_end/cm/codemirror.js(2856,10): error TS2365: Operator '+' cannot be applied to types 'null' and '0 | 1'. +node_modules/chrome-devtools-frontend/front_end/cm/codemirror.js(2856,10): error TS2365: Operator '+' cannot be applied to types 'null' and '1 | 0'. node_modules/chrome-devtools-frontend/front_end/cm/codemirror.js(2858,32): error TS2339: Property 'left' does not exist on type 'never'. node_modules/chrome-devtools-frontend/front_end/cm/codemirror.js(2858,49): error TS2339: Property 'right' does not exist on type 'never'. node_modules/chrome-devtools-frontend/front_end/cm/codemirror.js(3034,25): error TS2339: Property 'xRel' does not exist on type 'Pos'. @@ -6628,8 +6626,6 @@ node_modules/chrome-devtools-frontend/front_end/heap_snapshot_worker/HeapSnapsho Type 'HeapSnapshotNode' is not assignable to type '{ itemIndex(): number; serialize(): any; }'. Property '_snapshot' does not exist on type '{ itemIndex(): number; serialize(): any; }'. node_modules/chrome-devtools-frontend/front_end/heap_snapshot_worker/HeapSnapshot.js(2341,15): error TS2345: Argument of type 'HeapSnapshotNodeIndexProvider' is not assignable to parameter of type '{ itemForIndex(newIndex: number): { itemIndex(): number; serialize(): any; }; }'. - Types of property 'itemForIndex' are incompatible. - Type '(index: number) => HeapSnapshotNode' is not assignable to type '(newIndex: number) => { itemIndex(): number; serialize(): any; }'. node_modules/chrome-devtools-frontend/front_end/heap_snapshot_worker/HeapSnapshot.js(2353,12): error TS2339: Property 'nodeIndex' does not exist on type 'void'. node_modules/chrome-devtools-frontend/front_end/heap_snapshot_worker/HeapSnapshot.js(2354,16): error TS2339: Property 'id' does not exist on type 'void'. node_modules/chrome-devtools-frontend/front_end/heap_snapshot_worker/HeapSnapshot.js(2397,13): error TS2339: Property 'nodeIndex' does not exist on type 'void'. @@ -7714,9 +7710,6 @@ node_modules/chrome-devtools-frontend/front_end/network_log/NetworkLog.js(44,57) Type 'T' is not assignable to type 'NetworkManager'. node_modules/chrome-devtools-frontend/front_end/network_log/NetworkLog.js(99,59): error TS2345: Argument of type 'this' is not assignable to parameter of type '{ modelAdded(model: T): void; modelRemoved(model: T): void; }'. node_modules/chrome-devtools-frontend/front_end/network_log/NetworkLog.js(101,61): error TS2345: Argument of type 'this' is not assignable to parameter of type '{ modelAdded(model: T): void; modelRemoved(model: T): void; }'. - Type 'NetworkLog' is not assignable to type '{ modelAdded(model: T): void; modelRemoved(model: T): void; }'. - Types of property 'modelAdded' are incompatible. - Type '(networkManager: NetworkManager) => void' is not assignable to type '(model: T) => void'. node_modules/chrome-devtools-frontend/front_end/network_log/NetworkLog.js(123,24): error TS2694: Namespace 'Protocol' has no exported member 'Network'. node_modules/chrome-devtools-frontend/front_end/network_log/NetworkLog.js(154,49): error TS2694: Namespace 'NetworkLog.NetworkLog' has no exported member '_InitiatorInfo'. node_modules/chrome-devtools-frontend/front_end/network_log/NetworkLog.js(165,38): error TS2694: Namespace 'NetworkLog.NetworkLog' has no exported member '_InitiatorInfo'. @@ -10842,7 +10835,7 @@ node_modules/chrome-devtools-frontend/front_end/settings/SettingsScreen.js(45,10 node_modules/chrome-devtools-frontend/front_end/settings/SettingsScreen.js(46,24): error TS2555: Expected at least 2 arguments, but got 1. node_modules/chrome-devtools-frontend/front_end/settings/SettingsScreen.js(54,43): error TS2555: Expected at least 2 arguments, but got 1. node_modules/chrome-devtools-frontend/front_end/settings/SettingsScreen.js(69,55): error TS2339: Property 'runtime' does not exist on type 'Window'. -node_modules/chrome-devtools-frontend/front_end/settings/SettingsScreen.js(85,5): error TS2739: Type '{ tabbedPane(): TabbedPane; enableMoreTabsButton(): void; }' is missing the following properties from type '{ appendApplicableItems(locationName: string): void; appendView(view: { viewId(): string; title(): string; isCloseable(): boolean; isTransient(): boolean; toolbarItems(): Promise; widget(): Promise<...>; disposeView(): void; }, insertBefore?: { ...; }): void; showView(view: { ...; }, insertBefore?: { ...': appendApplicableItems, appendView, showView, removeView, widget +node_modules/chrome-devtools-frontend/front_end/settings/SettingsScreen.js(85,5): error TS2322: Type '{ tabbedPane(): TabbedPane; enableMoreTabsButton(): void; }' is not assignable to type '{ appendApplicableItems(locationName: string): void; appendView(view: { viewId(): string; title(): string; isCloseable(): boolean; isTransient(): boolean; toolbarItems(): Promise; widget(): Promise<...>; disposeView(): void; }, insertBefore?: { ...; }): void; showView(view: { ...; }, insertBefore?: { ...'. node_modules/chrome-devtools-frontend/front_end/settings/SettingsScreen.js(100,15): error TS2339: Property 'keyCode' does not exist on type 'Event'. node_modules/chrome-devtools-frontend/front_end/settings/SettingsScreen.js(119,31): error TS2339: Property 'createChild' does not exist on type 'Element'. node_modules/chrome-devtools-frontend/front_end/settings/SettingsScreen.js(121,42): error TS2339: Property 'createChild' does not exist on type 'Element'. @@ -11369,7 +11362,7 @@ node_modules/chrome-devtools-frontend/front_end/sources/SourcesPanel.js(133,55): node_modules/chrome-devtools-frontend/front_end/sources/SourcesPanel.js(208,22): error TS2694: Namespace 'Common' has no exported member 'Event'. node_modules/chrome-devtools-frontend/front_end/sources/SourcesPanel.js(227,52): error TS2339: Property '_instance' does not exist on type 'typeof WrapperView'. node_modules/chrome-devtools-frontend/front_end/sources/SourcesPanel.js(242,40): error TS2339: Property '_instance' does not exist on type 'typeof WrapperView'. -node_modules/chrome-devtools-frontend/front_end/sources/SourcesPanel.js(257,7): error TS2739: Type '{ tabbedPane(): TabbedPane; enableMoreTabsButton(): void; }' is missing the following properties from type '{ appendApplicableItems(locationName: string): void; appendView(view: { viewId(): string; title(): string; isCloseable(): boolean; isTransient(): boolean; toolbarItems(): Promise; widget(): Promise<...>; disposeView(): void; }, insertBefore?: { ...; }): void; showView(view: { ...; }, insertBefore?: { ...': appendApplicableItems, appendView, showView, removeView, widget +node_modules/chrome-devtools-frontend/front_end/sources/SourcesPanel.js(257,7): error TS2322: Type '{ tabbedPane(): TabbedPane; enableMoreTabsButton(): void; }' is not assignable to type '{ appendApplicableItems(locationName: string): void; appendView(view: { viewId(): string; title(): string; isCloseable(): boolean; isTransient(): boolean; toolbarItems(): Promise; widget(): Promise<...>; disposeView(): void; }, insertBefore?: { ...; }): void; showView(view: { ...; }, insertBefore?: { ...'. node_modules/chrome-devtools-frontend/front_end/sources/SourcesPanel.js(277,20): error TS2339: Property 'window' does not exist on type 'Element'. node_modules/chrome-devtools-frontend/front_end/sources/SourcesPanel.js(289,22): error TS2694: Namespace 'Common' has no exported member 'Event'. node_modules/chrome-devtools-frontend/front_end/sources/SourcesPanel.js(330,22): error TS2694: Namespace 'Common' has no exported member 'Event'. @@ -12891,8 +12884,8 @@ node_modules/chrome-devtools-frontend/front_end/ui/InspectorView.js(53,50): erro node_modules/chrome-devtools-frontend/front_end/ui/InspectorView.js(69,40): error TS2555: Expected at least 2 arguments, but got 1. node_modules/chrome-devtools-frontend/front_end/ui/InspectorView.js(80,24): error TS2694: Namespace 'Common' has no exported member 'Event'. node_modules/chrome-devtools-frontend/front_end/ui/InspectorView.js(92,51): error TS2339: Property 'runtime' does not exist on type 'Window'. -node_modules/chrome-devtools-frontend/front_end/ui/InspectorView.js(116,7): error TS2739: Type '{ tabbedPane(): TabbedPane; enableMoreTabsButton(): void; }' is missing the following properties from type '{ appendApplicableItems(locationName: string): void; appendView(view: { viewId(): string; title(): string; isCloseable(): boolean; isTransient(): boolean; toolbarItems(): Promise; widget(): Promise<...>; disposeView(): void; }, insertBefore?: { ...; }): void; showView(view: { ...; }, insertBefore?: { ...': appendApplicableItems, appendView, showView, removeView, widget -node_modules/chrome-devtools-frontend/front_end/ui/InspectorView.js(118,7): error TS2739: Type '{ tabbedPane(): TabbedPane; enableMoreTabsButton(): void; }' is missing the following properties from type '{ appendApplicableItems(locationName: string): void; appendView(view: { viewId(): string; title(): string; isCloseable(): boolean; isTransient(): boolean; toolbarItems(): Promise; widget(): Promise<...>; disposeView(): void; }, insertBefore?: { ...; }): void; showView(view: { ...; }, insertBefore?: { ...': appendApplicableItems, appendView, showView, removeView, widget +node_modules/chrome-devtools-frontend/front_end/ui/InspectorView.js(116,7): error TS2322: Type '{ tabbedPane(): TabbedPane; enableMoreTabsButton(): void; }' is not assignable to type '{ appendApplicableItems(locationName: string): void; appendView(view: { viewId(): string; title(): string; isCloseable(): boolean; isTransient(): boolean; toolbarItems(): Promise; widget(): Promise<...>; disposeView(): void; }, insertBefore?: { ...; }): void; showView(view: { ...; }, insertBefore?: { ...'. +node_modules/chrome-devtools-frontend/front_end/ui/InspectorView.js(118,7): error TS2322: Type '{ tabbedPane(): TabbedPane; enableMoreTabsButton(): void; }' is not assignable to type '{ appendApplicableItems(locationName: string): void; appendView(view: { viewId(): string; title(): string; isCloseable(): boolean; isTransient(): boolean; toolbarItems(): Promise; widget(): Promise<...>; disposeView(): void; }, insertBefore?: { ...; }): void; showView(view: { ...; }, insertBefore?: { ...'. node_modules/chrome-devtools-frontend/front_end/ui/InspectorView.js(247,73): error TS2339: Property 'altKey' does not exist on type 'Event'. node_modules/chrome-devtools-frontend/front_end/ui/InspectorView.js(247,89): error TS2339: Property 'shiftKey' does not exist on type 'Event'. node_modules/chrome-devtools-frontend/front_end/ui/InspectorView.js(254,17): error TS2339: Property 'keyCode' does not exist on type 'Event'. diff --git a/tests/baselines/reference/user/prettier.log b/tests/baselines/reference/user/prettier.log index 6ee6e91cb6b..2082b66ee59 100644 --- a/tests/baselines/reference/user/prettier.log +++ b/tests/baselines/reference/user/prettier.log @@ -160,6 +160,13 @@ src/language-js/printer-estree.js(1892,20): error TS2345: Argument of type '{ ty src/language-js/printer-estree.js(1894,18): error TS2345: Argument of type '"while ("' is not assignable to parameter of type '{ type: string; id: any; contents: any; break: boolean; expandedStates: any; }'. src/language-js/printer-estree.js(1903,9): error TS2345: Argument of type '")"' is not assignable to parameter of type '{ type: string; id: any; contents: any; break: boolean; expandedStates: any; }'. src/language-js/printer-estree.js(2426,28): error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'. +src/language-js/printer-estree.js(2446,13): error TS2345: Argument of type '{ hasLineBreak: boolean; cells: never[]; }[]' is not assignable to parameter of type '{ cells: any; } | ConcatArray<{ cells: any; }>'. + Type '{ hasLineBreak: boolean; cells: never[]; }[]' is not assignable to type 'ConcatArray<{ cells: any; }>'. + Types of property 'slice' are incompatible. + Type '(start?: number | undefined, end?: number | undefined) => { hasLineBreak: boolean; cells: never[]; }[]' is not assignable to type '(start?: number | undefined, end?: number | undefined) => { cells: any; }[]'. + Type '{ hasLineBreak: boolean; cells: never[]; }[]' is not assignable to type '{ cells: any; }[]'. + Type '{ hasLineBreak: boolean; cells: never[]; }' is not assignable to type '{ cells: any; }'. + Property 'hasLineBreak' does not exist on type '{ cells: any; }'. src/language-js/printer-estree.js(3513,11): error TS2345: Argument of type 'never[] | { type: string; parts: any; }' is not assignable to parameter of type 'ConcatArray'. Type '{ type: string; parts: any; }' is not assignable to type 'ConcatArray'. src/language-js/printer-estree.js(4031,23): error TS2532: Object is possibly 'undefined'. diff --git a/tests/baselines/reference/user/uglify-js.log b/tests/baselines/reference/user/uglify-js.log index 3c98006c52f..038bb1174cf 100644 --- a/tests/baselines/reference/user/uglify-js.log +++ b/tests/baselines/reference/user/uglify-js.log @@ -27,41 +27,41 @@ node_modules/uglify-js/lib/compress.js(2044,59): error TS2554: Expected 0 argume node_modules/uglify-js/lib/compress.js(2082,53): error TS2345: Argument of type 'any[]' is not assignable to parameter of type '[number, number, ...never[]]'. Type 'any[]' is missing the following properties from type '[number, number, ...never[]]': 0, 1 node_modules/uglify-js/lib/compress.js(2230,34): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(2942,42): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(3395,38): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(3408,33): error TS2322: Type '"f"' is not assignable to type 'boolean'. -node_modules/uglify-js/lib/compress.js(3542,33): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(3595,29): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(3612,29): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. -node_modules/uglify-js/lib/compress.js(3637,75): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(3711,63): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(3832,12): error TS2339: Property 'push' does not exist on type 'TreeTransformer'. -node_modules/uglify-js/lib/compress.js(3897,38): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(3918,24): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. -node_modules/uglify-js/lib/compress.js(3928,28): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. -node_modules/uglify-js/lib/compress.js(4097,21): error TS2403: Subsequent variable declarations must have the same type. Variable 'defs' must be of type 'Dictionary & { set: (key: any, val: any) => Dictionary & { set: ...; add: (key: any, val: any) => Dictionary & { set: ...; add: ...; get: (key: any) => any; del: (key: any) => Dictionary & { set: ...; ... 8 more ...; toObject: () => any; }; ... 5 more ...; toObject: () => any; }; ... 7 more ...; toObject: () => any;...', but here has type 'any'. -node_modules/uglify-js/lib/compress.js(4149,17): error TS2447: The '|=' operator is not allowed for boolean types. Consider using '||' instead. -node_modules/uglify-js/lib/compress.js(4210,45): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(4320,33): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(4618,17): error TS2403: Subsequent variable declarations must have the same type. Variable 'body' must be of type 'any[]', but here has type 'any'. -node_modules/uglify-js/lib/compress.js(4702,37): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(4910,57): error TS2345: Argument of type 'any[]' is not assignable to parameter of type '[RegExp, (string | undefined)?]'. +node_modules/uglify-js/lib/compress.js(2949,42): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3402,38): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3415,33): error TS2322: Type '"f"' is not assignable to type 'boolean'. +node_modules/uglify-js/lib/compress.js(3549,33): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3602,29): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3619,29): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. +node_modules/uglify-js/lib/compress.js(3644,75): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3718,63): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3839,12): error TS2339: Property 'push' does not exist on type 'TreeTransformer'. +node_modules/uglify-js/lib/compress.js(3914,38): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(3935,24): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. +node_modules/uglify-js/lib/compress.js(3945,28): error TS2339: Property 'parent' does not exist on type 'TreeTransformer'. +node_modules/uglify-js/lib/compress.js(4114,21): error TS2403: Subsequent variable declarations must have the same type. Variable 'defs' must be of type 'Dictionary & { set: (key: any, val: any) => Dictionary & { set: ...; add: (key: any, val: any) => Dictionary & { set: ...; add: ...; get: (key: any) => any; del: (key: any) => Dictionary & { set: ...; ... 8 more ...; toObject: () => any; }; ... 5 more ...; toObject: () => any; }; ... 7 more ...; toObject: () => any;...', but here has type 'any'. +node_modules/uglify-js/lib/compress.js(4166,17): error TS2447: The '|=' operator is not allowed for boolean types. Consider using '||' instead. +node_modules/uglify-js/lib/compress.js(4229,45): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(4340,33): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(4638,17): error TS2403: Subsequent variable declarations must have the same type. Variable 'body' must be of type 'any[]', but here has type 'any'. +node_modules/uglify-js/lib/compress.js(4722,37): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(4930,57): error TS2345: Argument of type 'any[]' is not assignable to parameter of type '[RegExp, (string | undefined)?]'. Property '0' is missing in type 'any[]' but required in type '[RegExp, (string | undefined)?]'. -node_modules/uglify-js/lib/compress.js(5074,45): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(5081,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'code' must be of type 'string', but here has type '{ get: () => string; toString: () => string; indent: () => void; indentation: () => number; current_width: () => number; should_break: () => boolean; has_parens: () => boolean; newline: () => void; print: (str: any) => void; ... 24 more ...; parent: (n: any) => any; }'. -node_modules/uglify-js/lib/compress.js(5085,36): error TS2532: Object is possibly 'undefined'. -node_modules/uglify-js/lib/compress.js(5090,41): error TS2339: Property 'get' does not exist on type 'string'. -node_modules/uglify-js/lib/compress.js(5594,18): error TS2454: Variable 'is_strict_comparison' is used before being assigned. -node_modules/uglify-js/lib/compress.js(6105,25): error TS2367: This condition will always return 'false' since the types 'boolean' and '"f"' have no overlap. -node_modules/uglify-js/lib/compress.js(6132,47): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(6205,39): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(6277,39): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(6283,41): error TS2554: Expected 0 arguments, but got 1. -node_modules/uglify-js/lib/compress.js(6728,43): error TS2454: Variable 'property' is used before being assigned. -node_modules/uglify-js/lib/compress.js(6743,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'value' must be of type 'number', but here has type 'any'. -node_modules/uglify-js/lib/compress.js(6746,46): error TS2339: Property 'has_side_effects' does not exist on type 'number'. -node_modules/uglify-js/lib/compress.js(6752,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'value' must be of type 'number', but here has type 'any'. -node_modules/uglify-js/lib/compress.js(6790,34): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(5094,45): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(5101,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'code' must be of type 'string', but here has type '{ get: () => string; toString: () => string; indent: () => void; indentation: () => number; current_width: () => number; should_break: () => boolean; has_parens: () => boolean; newline: () => void; print: (str: any) => void; ... 24 more ...; parent: (n: any) => any; }'. +node_modules/uglify-js/lib/compress.js(5105,36): error TS2532: Object is possibly 'undefined'. +node_modules/uglify-js/lib/compress.js(5110,41): error TS2339: Property 'get' does not exist on type 'string'. +node_modules/uglify-js/lib/compress.js(5623,18): error TS2454: Variable 'is_strict_comparison' is used before being assigned. +node_modules/uglify-js/lib/compress.js(6134,25): error TS2367: This condition will always return 'false' since the types 'boolean' and '"f"' have no overlap. +node_modules/uglify-js/lib/compress.js(6161,47): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(6234,39): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(6306,39): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(6312,41): error TS2554: Expected 0 arguments, but got 1. +node_modules/uglify-js/lib/compress.js(6757,43): error TS2454: Variable 'property' is used before being assigned. +node_modules/uglify-js/lib/compress.js(6772,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'value' must be of type 'number', but here has type 'any'. +node_modules/uglify-js/lib/compress.js(6775,46): error TS2339: Property 'has_side_effects' does not exist on type 'number'. +node_modules/uglify-js/lib/compress.js(6781,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'value' must be of type 'number', but here has type 'any'. +node_modules/uglify-js/lib/compress.js(6819,34): error TS2554: Expected 0 arguments, but got 1. node_modules/uglify-js/lib/minify.js(167,75): error TS2339: Property 'compress' does not exist on type 'Compressor'. node_modules/uglify-js/lib/mozilla-ast.js(566,33): error TS2554: Expected 0 arguments, but got 1. node_modules/uglify-js/lib/output.js(235,25): error TS2554: Expected 0 arguments, but got 2. diff --git a/tests/baselines/reference/user/webpack.log b/tests/baselines/reference/user/webpack.log index 0cde6bb1623..ce91836eddf 100644 --- a/tests/baselines/reference/user/webpack.log +++ b/tests/baselines/reference/user/webpack.log @@ -1,10 +1,7 @@ Exit Code: 1 Standard output: -../../../../../built/local/lib.dom.d.ts(17676,19): error TS2451: Cannot redeclare block-scoped variable 'WebAssembly'. +../../../../../built/local/lib.dom.d.ts(17677,19): error TS2451: Cannot redeclare block-scoped variable 'WebAssembly'. declarations.d.ts(258,15): error TS2451: Cannot redeclare block-scoped variable 'WebAssembly'. -lib/ContextModuleFactory.js(253,50): error TS2339: Property 'concat' does not exist on type 'unknown'. -lib/web/JsonpChunkTemplatePlugin.js(13,6): error TS2339: Property 'id' does not exist on type 'unknown'. -lib/web/JsonpMainTemplatePlugin.js(501,11): error TS2339: Property 'id' does not exist on type 'unknown'. diff --git a/tests/baselines/reference/variableDeclarationDeclarationEmitUniqueSymbolPartialStatement.js b/tests/baselines/reference/variableDeclarationDeclarationEmitUniqueSymbolPartialStatement.js index 21871ff2304..872008368c6 100644 --- a/tests/baselines/reference/variableDeclarationDeclarationEmitUniqueSymbolPartialStatement.js +++ b/tests/baselines/reference/variableDeclarationDeclarationEmitUniqueSymbolPartialStatement.js @@ -16,8 +16,8 @@ var Foo = /** @class */ (function () { } return Foo; }()); -_a = key; exports.Foo = Foo; +_a = key; //// [variableDeclarationDeclarationEmitUniqueSymbolPartialStatement.d.ts] diff --git a/tests/cases/compiler/contravariantTypeAliasInference.ts b/tests/cases/compiler/contravariantTypeAliasInference.ts new file mode 100644 index 00000000000..77044eeae76 --- /dev/null +++ b/tests/cases/compiler/contravariantTypeAliasInference.ts @@ -0,0 +1,19 @@ +// @strict: true + +type Func1 = (x: T) => void; +type Func2 = ((x: T) => void) | undefined; + +declare let f1: Func1; +declare let f2: Func1<"a">; + +declare function foo(f1: Func1, f2: Func1): void; + +foo(f1, f2); + +declare let g1: Func2; +declare let g2: Func2<"a">; + +declare function bar(g1: Func2, g2: Func2): void; + +bar(f1, f2); +bar(g1, g2); diff --git a/tests/cases/compiler/declarationEmitForGlobalishSpecifierSymlink.ts b/tests/cases/compiler/declarationEmitForGlobalishSpecifierSymlink.ts new file mode 100644 index 00000000000..b42d679b521 --- /dev/null +++ b/tests/cases/compiler/declarationEmitForGlobalishSpecifierSymlink.ts @@ -0,0 +1,35 @@ +// @useCaseSensitiveFilenames: true +// @declaration: true +// @filename: /p1/node_modules/typescript-fsa/src/impl.d.ts +export function getA(): A; +export enum A { + Val +} +// @filename: /p1/node_modules/typescript-fsa/index.d.ts +export * from "./src/impl"; +// @filename: /p1/node_modules/typescript-fsa/package.json +{ + "name": "typescript-fsa", + "version": "1.0.0" +} +// @filename: /p2/node_modules/typescript-fsa/src/impl.d.ts +export function getA(): A; +export enum A { + Val +} +// @filename: /p2/node_modules/typescript-fsa/index.d.ts +export * from "./src/impl"; +// @filename: /p2/node_modules/typescript-fsa/package.json +{ + "name": "typescript-fsa", + "version": "1.0.0" +} +// @filename: /p1/index.ts +import * as _whatever from "p2"; +import { getA } from "typescript-fsa"; + +export const a = getA(); +// @filename: /p2/index.d.ts +export const a: import("typescript-fsa").A; + +// @link: /p2 -> /p1/node_modules/p2 diff --git a/tests/cases/compiler/declarationEmitForGlobalishSpecifierSymlink2.ts b/tests/cases/compiler/declarationEmitForGlobalishSpecifierSymlink2.ts new file mode 100644 index 00000000000..5b46de99622 --- /dev/null +++ b/tests/cases/compiler/declarationEmitForGlobalishSpecifierSymlink2.ts @@ -0,0 +1,25 @@ +// @useCaseSensitiveFilenames: true +// @declaration: true +// @filename: /cache/typescript-fsa/src/impl.d.ts +export function getA(): A; +export enum A { + Val +} +// @filename: /cache/typescript-fsa/index.d.ts +export * from "./src/impl"; +// @filename: /cache/typescript-fsa/package.json +{ + "name": "typescript-fsa", + "version": "1.0.0" +} +// @filename: /p1/index.ts +import * as _whatever from "p2"; +import { getA } from "typescript-fsa"; + +export const a = getA(); +// @filename: /p2/index.d.ts +export const a: import("typescript-fsa").A; + +// @link: /p2 -> /p1/node_modules/p2 +// @link: /cache/typescript-fsa -> /p1/node_modules/typescript-fsa +// @link: /cache/typescript-fsa -> /p2/node_modules/typescript-fsa diff --git a/tests/cases/compiler/destructuringAssignmentWithDefault.ts b/tests/cases/compiler/destructuringAssignmentWithDefault.ts index 45ade402eb8..76b0e71c373 100644 --- a/tests/cases/compiler/destructuringAssignmentWithDefault.ts +++ b/tests/cases/compiler/destructuringAssignmentWithDefault.ts @@ -2,3 +2,31 @@ const a: { x?: number } = { }; let x = 0; ({x = 1} = a); + +// Repro from #26235 + +function f1(options?: { color?: string, width?: number }) { + let { color, width } = options || {}; + ({ color, width } = options || {}); + let x1 = (options || {}).color; + let x2 = (options || {})["color"]; +} + +function f2(options?: [string?, number?]) { + let [str, num] = options || []; + [str, num] = options || []; + let x1 = (options || {})[0]; +} + +function f3(options?: { color: string, width: number }) { + let { color, width } = options || {}; + ({ color, width } = options || {}); + let x1 = (options || {}).color; + let x2 = (options || {})["color"]; +} + +function f4(options?: [string, number]) { + let [str, num] = options || []; + [str, num] = options || []; + let x1 = (options || {})[0]; +} diff --git a/tests/cases/compiler/identicalTypesNoDifferByCheckOrder.ts b/tests/cases/compiler/identicalTypesNoDifferByCheckOrder.ts new file mode 100644 index 00000000000..fbdf373a407 --- /dev/null +++ b/tests/cases/compiler/identicalTypesNoDifferByCheckOrder.ts @@ -0,0 +1,38 @@ +// @strictNullChecks: true + +interface SomeProps { + x?: string; + y?: number; + renderAs?: FunctionComponent1 +} + +type SomePropsX = Required> & Omit; + +interface SomePropsClone { + x?: string; + y?: number; + renderAs?: FunctionComponent2 +} + +type SomePropsCloneX = Required> & Omit; + +type Validator = {(): boolean, opt?: T}; +type WeakValidationMap = {[K in keyof T]?: null extends T[K] ? Validator : Validator}; + +interface FunctionComponent1

{ + (props: P & { children?: unknown }): void; + propTypes?: WeakValidationMap

; +} + +interface FunctionComponent2

{ + (props: P & { children?: unknown }): void; + propTypes?: WeakValidationMap

; +} + +function needsComponentOfSomeProps3(...x: SomePropsClone[]): void {} +const comp3: FunctionComponent2 = null as any; +needsComponentOfSomeProps3({ renderAs: comp3 }); + +function needsComponentOfSomeProps2(...x: SomeProps[]): void {} +const comp2: FunctionComponent1 = null as any; +needsComponentOfSomeProps2({ renderAs: comp2 }); \ No newline at end of file diff --git a/tests/cases/compiler/implicitIndexSignatures.ts b/tests/cases/compiler/implicitIndexSignatures.ts index 2e36a91bada..2239ad8a8e2 100644 --- a/tests/cases/compiler/implicitIndexSignatures.ts +++ b/tests/cases/compiler/implicitIndexSignatures.ts @@ -43,3 +43,15 @@ function f4() { const v3 = getNumberIndexValue(o1); const v4 = getNumberIndexValue(o2); } + +function f5() { + enum E1 { A, B } + enum E2 { A = "A", B = "B" } + enum E3 { A = 0, B = "B" } + const v1 = getStringIndexValue(E1); + const v2 = getStringIndexValue(E2); + const v3 = getStringIndexValue(E3); + const v4 = getNumberIndexValue(E1); + const v5 = getNumberIndexValue(E2); + const v6 = getNumberIndexValue(E3); +} diff --git a/tests/cases/compiler/inferFromGenericFunctionReturnTypes3.ts b/tests/cases/compiler/inferFromGenericFunctionReturnTypes3.ts index 429d98b6a39..d14111c7a7a 100644 --- a/tests/cases/compiler/inferFromGenericFunctionReturnTypes3.ts +++ b/tests/cases/compiler/inferFromGenericFunctionReturnTypes3.ts @@ -182,3 +182,22 @@ enum State { A, B } type Foo = { state: State } declare function bar(f: () => T[]): T[]; let x: Foo[] = bar(() => !!true ? [{ state: State.A }] : [{ state: State.B }]); // Error + +// Repros from #31443 + +enum Enum { A, B } + +class ClassWithConvert { + constructor(val: T) { } + convert(converter: { to: (v: T) => T; }) { } +} + +function fn(arg: ClassWithConvert, f: () => ClassWithConvert) { } +fn(new ClassWithConvert(Enum.A), () => new ClassWithConvert(Enum.A)); + +type Func = (x: T) => T; + +declare function makeFoo(x: T): Func; +declare function baz(x: Func, y: Func): void; + +baz(makeFoo(Enum.A), makeFoo(Enum.A)); diff --git a/tests/cases/compiler/inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts b/tests/cases/compiler/inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts new file mode 100644 index 00000000000..98c0f25ee7b --- /dev/null +++ b/tests/cases/compiler/inferenceDoesntCompareAgainstUninstantiatedTypeParameter.ts @@ -0,0 +1,33 @@ +class ClassA { + constructor(private entity?: TEntityClass, public settings?: SettingsInterface) { + + } +} +export interface ValueInterface { + func?: (row: TValueClass) => any; + value?: string; +} +export interface SettingsInterface { + values?: (row: TClass) => ValueInterface[], +} +class ConcreteClass { + theName = 'myClass'; +} + +var thisGetsTheFalseError = new ClassA(new ConcreteClass(), { + values: o => [ + { + value: o.theName, + func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' + } + ] +}); + +var thisIsOk = new ClassA(new ConcreteClass(), { + values: o => [ + { + value: o.theName, + func: x => 'asdfkjhgfdfghjkjhgfdfghjklkjhgfdfghjklkjhgfghj' + } + ] +}); \ No newline at end of file diff --git a/tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts b/tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts index 1cd967c294f..5e1b9430088 100644 --- a/tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts +++ b/tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts @@ -22,3 +22,23 @@ e['hello'] = 'modified'; e['hello'] += 1; e['hello'] ++; +const o = { a: 0 }; + +declare const k: "a" | "b" | "c"; +o[k]; + + +declare const k2: "c"; +o[k2]; + +declare const sym : unique symbol; +o[sym]; + +enum NumEnum { a, b } +let numEnumKey: NumEnum; +o[numEnumKey]; + + +enum StrEnum { a = "a", b = "b" } +let strEnumKey: StrEnum; +o[strEnumKey]; diff --git a/tests/cases/compiler/noImplicitThisBigThis.ts b/tests/cases/compiler/noImplicitThisBigThis.ts new file mode 100644 index 00000000000..687f2f9355d --- /dev/null +++ b/tests/cases/compiler/noImplicitThisBigThis.ts @@ -0,0 +1,50 @@ +// @declaration: true +// @noImplicitThis: true + +// https://github.com/microsoft/TypeScript/issues/29902 + +function createObj() { + return { + func1() { + return this; + }, + func2() { + return this; + }, + func3() { + return this; + } + }; +} + +function createObjNoCrash() { + return { + func1() { + return this; + }, + func2() { + return this; + }, + func3() { + return this; + }, + func4() { + return this; + }, + func5() { + return this; + }, + func6() { + return this; + }, + func7() { + return this; + }, + func8() { + return this; + }, + func9() { + return this; + } + }; +} diff --git a/tests/cases/compiler/normalizedIntersectionTooComplex.ts b/tests/cases/compiler/normalizedIntersectionTooComplex.ts new file mode 100644 index 00000000000..dff8bb12019 --- /dev/null +++ b/tests/cases/compiler/normalizedIntersectionTooComplex.ts @@ -0,0 +1,38 @@ +// @strict: true + +// Repro from #30050 + +interface Obj { + ref: T; +} +interface Func { + (x: T): void; +} +type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; +type CtorOf = (arg: UnionToIntersection) => T; + +interface Big { + "0": { common?: string; "0"?: number, ref?: Obj | Func; } + "1": { common?: string; "1"?: number, ref?: Obj | Func; } + "2": { common?: string; "2"?: number, ref?: Obj | Func; } + "3": { common?: string; "3"?: number, ref?: Obj | Func; } + "4": { common?: string; "4"?: number, ref?: Obj | Func; } + "5": { common?: string; "5"?: number, ref?: Obj | Func; } + "6": { common?: string; "6"?: number, ref?: Obj | Func; } + "7": { common?: string; "7"?: number, ref?: Obj | Func; } + "8": { common?: string; "8"?: number, ref?: Obj | Func; } + "9": { common?: string; "9"?: number, ref?: Obj | Func; } + "10": { common?: string; "10"?: number, ref?: Obj | Func; } + "11": { common?: string; "11"?: number, ref?: Obj | Func; } + "12": { common?: string; "12"?: number, ref?: Obj | Func; } + "13": { common?: string; "13"?: number, ref?: Obj | Func; } + "14": { common?: string; "14"?: number, ref?: Obj | Func; } + "15": { common?: string; "15"?: number, ref?: Obj | Func; } + "16": { common?: string; "16"?: number, ref?: Obj | Func; } + "17": { common?: string; "17"?: number, ref?: Obj | Func; } +} +declare function getCtor(comp: T): CtorOf + +declare var all: keyof Big; +const ctor = getCtor(all); +const comp = ctor({ common: "ok", ref: x => console.log(x) }); diff --git a/tests/cases/compiler/reactTagNameComponentWithPropsNoOOM.tsx b/tests/cases/compiler/reactTagNameComponentWithPropsNoOOM.tsx new file mode 100644 index 00000000000..e6011974230 --- /dev/null +++ b/tests/cases/compiler/reactTagNameComponentWithPropsNoOOM.tsx @@ -0,0 +1,13 @@ +// @jsx: react +// @strict: true +/// + +import * as React from "react"; +declare const Tag: keyof React.ReactHTML; + +const classes = ""; +const rest: {} = {}; +const children: any[] = []; + +{children} + \ No newline at end of file diff --git a/tests/cases/compiler/reactTagNameComponentWithPropsNoOOM2.tsx b/tests/cases/compiler/reactTagNameComponentWithPropsNoOOM2.tsx new file mode 100644 index 00000000000..64d46b5dd95 --- /dev/null +++ b/tests/cases/compiler/reactTagNameComponentWithPropsNoOOM2.tsx @@ -0,0 +1,13 @@ +// @jsx: react +// @strict: true +/// + +import * as React from "react"; +declare const Tag: keyof React.ReactHTML; + +const classes = ""; +const rest: React.HTMLAttributes = {}; +const children: any[] = []; + +{children} + \ No newline at end of file diff --git a/tests/cases/conformance/moduleResolution/typesVersions.emptyTypes.ts b/tests/cases/conformance/moduleResolution/typesVersions.emptyTypes.ts new file mode 100644 index 00000000000..f5d0792bfc4 --- /dev/null +++ b/tests/cases/conformance/moduleResolution/typesVersions.emptyTypes.ts @@ -0,0 +1,18 @@ +// @baseUrl: / +// @traceResolution: true +// @target: esnext +// @module: commonjs + +// @filename: /a/package.json +{ + "types": "", + "typesVersions": { + ">=3.1.0-0": { "*" : ["ts3.1/*"] } + } +} + +// @filename: /a/ts3.1/index.d.ts +export const a = 0; + +// @filename: /b/user.ts +import { a } from "a"; diff --git a/tests/cases/conformance/types/intersection/intersectionTypeMembers.ts b/tests/cases/conformance/types/intersection/intersectionTypeMembers.ts index a350c657f61..bfb257b8ac2 100644 --- a/tests/cases/conformance/types/intersection/intersectionTypeMembers.ts +++ b/tests/cases/conformance/types/intersection/intersectionTypeMembers.ts @@ -42,3 +42,25 @@ const de: D & E = { other: { g: 101 } } } + +// Additional test case with >2 doubly nested members so fix for #31441 is tested w/ excess props +interface F { + nested: { doublyNested: { g: string; } } +} + +interface G { + nested: { doublyNested: { h: string; } } +} + +const defg: D & E & F & G = { + nested: { + doublyNested: { + d: 'yes', + f: 'no', + g: 'ok', + h: 'affirmative' + }, + different: { e: 12 }, + other: { g: 101 } + } +} diff --git a/tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts b/tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts index 898648cea44..b242aa3de60 100644 --- a/tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts +++ b/tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts @@ -139,11 +139,12 @@ function fn4() { let y: ReadonlyArray[K] = 'abc'; } -// Repro from #31439 +// Repro from #31439 and #31691 export class c { [x: string]: string; constructor() { + this.a = "b"; this["a"] = "b"; } } diff --git a/tests/cases/conformance/types/union/unionTypeCallSignatures5.ts b/tests/cases/conformance/types/union/unionTypeCallSignatures5.ts new file mode 100644 index 00000000000..30a5ac031ad --- /dev/null +++ b/tests/cases/conformance/types/union/unionTypeCallSignatures5.ts @@ -0,0 +1,12 @@ +// #31485 +interface A { + (this: void, b?: number): void; +} +interface B { + (this: number, b?: number): void; +} +interface C { + (i: number): void; +} +declare const fn: A | B | C; +fn(0); diff --git a/tests/cases/fourslash/completionsStringsWithTriggerCharacter.ts b/tests/cases/fourslash/completionsStringsWithTriggerCharacter.ts new file mode 100644 index 00000000000..277218305f4 --- /dev/null +++ b/tests/cases/fourslash/completionsStringsWithTriggerCharacter.ts @@ -0,0 +1,30 @@ +/// + +//// type A = "a/b" | "b/a"; +//// const a: A = "a/*1*/"; +//// +//// type B = "a@b" | "b@a"; +//// const a: B = "a@/*2*/"; +//// +//// type C = "a.b" | "b.a"; +//// const c: C = "a./*3*/"; +//// +//// type D = "a'b" | "b'a"; +//// const d: D = "a'/*4*/"; +//// +//// type E = "a`b" | "b`a"; +//// const e: E = "a`/*5*/"; +//// +//// type F = 'a"b' | 'b"a'; +//// const f: F = 'a"/*6*/'; +//// +//// type G = "a; + marker?: ArrayOrSingle; /** @default 1 */ overloadsCount?: number; docComment?: string; diff --git a/tests/cases/fourslash/signatureHelpJSX.ts b/tests/cases/fourslash/signatureHelpJSX.ts new file mode 100644 index 00000000000..181ff85541b --- /dev/null +++ b/tests/cases/fourslash/signatureHelpJSX.ts @@ -0,0 +1,10 @@ +/// + +//@Filename: test.tsx +//@jsx: react +////declare var React: any; +////const z =

{[].map(x =>