When caching type references cache the tracked symbols so they can be emitted in the d.ts file (#51721)

This commit is contained in:
Sheetal Nandi 2023-10-25 15:05:47 -07:00 committed by GitHub
parent 043e1ca743
commit 55395f9e01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 449 additions and 1 deletions

View File

@ -1010,6 +1010,7 @@ import {
tokenToString,
tracing,
TracingNode,
TrackedSymbol,
TransientSymbol,
TransientSymbolLinks,
tryAddToSet,
@ -6424,6 +6425,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
symbolDepth: undefined,
inferTypeParameters: undefined,
approximateLength: 0,
trackedSymbols: undefined,
};
context.tracker = new SymbolTrackerImpl(context, tracker, moduleResolverHost);
const resultingNode = cb(context);
@ -6922,6 +6924,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
const cachedResult = links?.serializedTypes?.get(key);
if (cachedResult) {
// TODO:: check if we instead store late painted statements associated with this?
cachedResult.trackedSymbols?.forEach(
([symbol, enclosingDeclaration, meaning]) =>
context.tracker.trackSymbol(
symbol,
enclosingDeclaration,
meaning,
),
);
if (cachedResult.truncating) {
context.truncating = true;
}
@ -6942,7 +6953,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const result = transform(type);
const addedLength = context.approximateLength - startLength;
if (!context.reportedDiagnostic && !context.encounteredError) {
links?.serializedTypes?.set(key, { node: result, truncating: context.truncating, addedLength });
links?.serializedTypes?.set(key, {
node: result,
truncating: context.truncating,
addedLength,
trackedSymbols: context.trackedSymbols,
});
}
context.visitedTypes.delete(typeId);
if (id) {
@ -8860,6 +8876,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (context.reportedDiagnostic) {
oldcontext.reportedDiagnostic = context.reportedDiagnostic; // hoist diagnostic result into outer context
}
if (context.trackedSymbols) {
if (!oldContext.trackedSymbols) oldContext.trackedSymbols = context.trackedSymbols;
else Debug.assert(context.trackedSymbols === oldContext.trackedSymbols);
}
context = oldContext;
}
}
@ -50378,6 +50398,7 @@ interface NodeBuilderContext {
// State
encounteredError: boolean;
reportedDiagnostic: boolean;
trackedSymbols: TrackedSymbol[] | undefined;
visitedTypes: Set<number> | undefined;
symbolDepth: Map<string, number> | undefined;
inferTypeParameters: TypeParameter[] | undefined;
@ -50418,6 +50439,8 @@ class SymbolTrackerImpl implements SymbolTracker {
this.onDiagnosticReported();
return true;
}
// Skip recording type parameters as they dont contribute to late painted statements
if (!(symbol.flags & SymbolFlags.TypeParameter)) (this.context.trackedSymbols ??= []).push([symbol, enclosingDeclaration, meaning]);
}
return false;
}

View File

@ -6031,11 +6031,14 @@ export interface NodeLinks {
assertionExpressionType?: Type; // Cached type of the expression of a type assertion
}
/** @internal */
export type TrackedSymbol = [symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags];
/** @internal */
export interface SerializedTypeEntry {
node: TypeNode;
truncating?: boolean;
addedLength: number;
trackedSymbols: readonly TrackedSymbol[] | undefined;
}
// dprint-ignore

View File

@ -908,4 +908,55 @@ console.log(a);`,
}],
baselinePrograms: true,
});
verifyTsc({
scenario: "incremental",
subScenario: "generates typerefs correctly",
commandLineArgs: ["-p", `/src/project`],
fs: () =>
loadProjectFromFiles({
"/src/project/tsconfig.json": jsonToReadableText({
compilerOptions: {
composite: true,
outDir: "outDir",
checkJs: true,
},
include: ["src"],
}),
"/src/project/src/box.ts": Utils.dedent`
export interface Box<T> {
unbox(): T
}
`,
"/src/project/src/bug.js": Utils.dedent`
import * as B from "./box.js"
import * as W from "./wrap.js"
/**
* @template {object} C
* @param {C} source
* @returns {W.Wrap<C>}
*/
const wrap = source => {
throw source
}
/**
* @returns {B.Box<number>}
*/
const box = (n = 0) => ({ unbox: () => n })
export const bug = wrap({ n: box(1) });
`,
"/src/project/src/wrap.ts": Utils.dedent`
export type Wrap<C> = {
[K in keyof C]: { wrapped: C[K] }
}
`,
}),
edits: [{
caption: "modify js file",
edit: fs => appendText(fs, "/src/project/src/bug.js", `export const something = 1;`),
}],
});
});

View File

@ -0,0 +1,371 @@
currentDirectory:: / useCaseSensitiveFileNames: false
Input::
//// [/lib/lib.d.ts]
/// <reference no-default-lib="true"/>
interface Boolean {}
interface Function {}
interface CallableFunction {}
interface NewableFunction {}
interface IArguments {}
interface Number { toExponential: any; }
interface Object {}
interface RegExp {}
interface String { charAt: any; }
interface Array<T> { length: number; [n: number]: T; }
interface ReadonlyArray<T> {}
declare const console: { log(msg: any): void; };
//// [/src/project/src/box.ts]
export interface Box<T> {
unbox(): T
}
//// [/src/project/src/bug.js]
import * as B from "./box.js"
import * as W from "./wrap.js"
/**
* @template {object} C
* @param {C} source
* @returns {W.Wrap<C>}
*/
const wrap = source => {
throw source
}
/**
* @returns {B.Box<number>}
*/
const box = (n = 0) => ({ unbox: () => n })
export const bug = wrap({ n: box(1) });
//// [/src/project/src/wrap.ts]
export type Wrap<C> = {
[K in keyof C]: { wrapped: C[K] }
}
//// [/src/project/tsconfig.json]
{
"compilerOptions": {
"composite": true,
"outDir": "outDir",
"checkJs": true
},
"include": [
"src"
]
}
Output::
/lib/tsc -p /src/project
exitCode:: ExitStatus.Success
//// [/src/project/outDir/src/box.d.ts]
export interface Box<T> {
unbox(): T;
}
//// [/src/project/outDir/src/box.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//// [/src/project/outDir/src/bug.d.ts]
export const bug: W.Wrap<{
n: B.Box<number>;
}>;
import * as B from "./box.js";
import * as W from "./wrap.js";
//// [/src/project/outDir/src/bug.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.bug = void 0;
var B = require("./box.js");
var W = require("./wrap.js");
/**
* @template {object} C
* @param {C} source
* @returns {W.Wrap<C>}
*/
var wrap = function (source) {
throw source;
};
/**
* @returns {B.Box<number>}
*/
var box = function (n) {
if (n === void 0) { n = 0; }
return ({ unbox: function () { return n; } });
};
exports.bug = wrap({ n: box(1) });
//// [/src/project/outDir/src/wrap.d.ts]
export type Wrap<C> = {
[K in keyof C]: {
wrapped: C[K];
};
};
//// [/src/project/outDir/src/wrap.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//// [/src/project/outDir/tsconfig.tsbuildinfo]
{"program":{"fileNames":["../../../lib/lib.d.ts","../src/box.ts","../src/wrap.ts","../src/bug.js"],"fileInfos":[{"version":"3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true},{"version":"-14267342128-export interface Box<T> {\n unbox(): T\n}\n","signature":"-15554117365-export interface Box<T> {\n unbox(): T;\n}\n"},{"version":"-7208318765-export type Wrap<C> = {\n [K in keyof C]: { wrapped: C[K] }\n}\n","signature":"-7604652776-export type Wrap<C> = {\n [K in keyof C]: {\n wrapped: C[K];\n };\n};\n"},{"version":"-27771690375-import * as B from \"./box.js\"\nimport * as W from \"./wrap.js\"\n\n/**\n * @template {object} C\n * @param {C} source\n * @returns {W.Wrap<C>}\n */\nconst wrap = source => {\nthrow source\n}\n\n/**\n * @returns {B.Box<number>}\n */\nconst box = (n = 0) => ({ unbox: () => n })\n\nexport const bug = wrap({ n: box(1) });\n","signature":"-2569667161-export const bug: W.Wrap<{\n n: B.Box<number>;\n}>;\nimport * as B from \"./box.js\";\nimport * as W from \"./wrap.js\";\n"}],"root":[[2,4]],"options":{"checkJs":true,"composite":true,"outDir":"./"},"fileIdsList":[[2,3]],"referencedMap":[[4,1]],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[1,2,4,3],"latestChangedDtsFile":"./src/bug.d.ts"},"version":"FakeTSVersion"}
//// [/src/project/outDir/tsconfig.tsbuildinfo.readable.baseline.txt]
{
"program": {
"fileNames": [
"../../../lib/lib.d.ts",
"../src/box.ts",
"../src/wrap.ts",
"../src/bug.js"
],
"fileNamesList": [
[
"../src/box.ts",
"../src/wrap.ts"
]
],
"fileInfos": {
"../../../lib/lib.d.ts": {
"original": {
"version": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"affectsGlobalScope": true
},
"version": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"signature": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"affectsGlobalScope": true
},
"../src/box.ts": {
"original": {
"version": "-14267342128-export interface Box<T> {\n unbox(): T\n}\n",
"signature": "-15554117365-export interface Box<T> {\n unbox(): T;\n}\n"
},
"version": "-14267342128-export interface Box<T> {\n unbox(): T\n}\n",
"signature": "-15554117365-export interface Box<T> {\n unbox(): T;\n}\n"
},
"../src/wrap.ts": {
"original": {
"version": "-7208318765-export type Wrap<C> = {\n [K in keyof C]: { wrapped: C[K] }\n}\n",
"signature": "-7604652776-export type Wrap<C> = {\n [K in keyof C]: {\n wrapped: C[K];\n };\n};\n"
},
"version": "-7208318765-export type Wrap<C> = {\n [K in keyof C]: { wrapped: C[K] }\n}\n",
"signature": "-7604652776-export type Wrap<C> = {\n [K in keyof C]: {\n wrapped: C[K];\n };\n};\n"
},
"../src/bug.js": {
"original": {
"version": "-27771690375-import * as B from \"./box.js\"\nimport * as W from \"./wrap.js\"\n\n/**\n * @template {object} C\n * @param {C} source\n * @returns {W.Wrap<C>}\n */\nconst wrap = source => {\nthrow source\n}\n\n/**\n * @returns {B.Box<number>}\n */\nconst box = (n = 0) => ({ unbox: () => n })\n\nexport const bug = wrap({ n: box(1) });\n",
"signature": "-2569667161-export const bug: W.Wrap<{\n n: B.Box<number>;\n}>;\nimport * as B from \"./box.js\";\nimport * as W from \"./wrap.js\";\n"
},
"version": "-27771690375-import * as B from \"./box.js\"\nimport * as W from \"./wrap.js\"\n\n/**\n * @template {object} C\n * @param {C} source\n * @returns {W.Wrap<C>}\n */\nconst wrap = source => {\nthrow source\n}\n\n/**\n * @returns {B.Box<number>}\n */\nconst box = (n = 0) => ({ unbox: () => n })\n\nexport const bug = wrap({ n: box(1) });\n",
"signature": "-2569667161-export const bug: W.Wrap<{\n n: B.Box<number>;\n}>;\nimport * as B from \"./box.js\";\nimport * as W from \"./wrap.js\";\n"
}
},
"root": [
[
[
2,
4
],
[
"../src/box.ts",
"../src/wrap.ts",
"../src/bug.js"
]
]
],
"options": {
"checkJs": true,
"composite": true,
"outDir": "./"
},
"referencedMap": {
"../src/bug.js": [
"../src/box.ts",
"../src/wrap.ts"
]
},
"exportedModulesMap": {},
"semanticDiagnosticsPerFile": [
"../../../lib/lib.d.ts",
"../src/box.ts",
"../src/bug.js",
"../src/wrap.ts"
],
"latestChangedDtsFile": "./src/bug.d.ts"
},
"version": "FakeTSVersion",
"size": 1698
}
Change:: modify js file
Input::
//// [/src/project/src/bug.js]
import * as B from "./box.js"
import * as W from "./wrap.js"
/**
* @template {object} C
* @param {C} source
* @returns {W.Wrap<C>}
*/
const wrap = source => {
throw source
}
/**
* @returns {B.Box<number>}
*/
const box = (n = 0) => ({ unbox: () => n })
export const bug = wrap({ n: box(1) });
export const something = 1;
Output::
/lib/tsc -p /src/project
exitCode:: ExitStatus.Success
//// [/src/project/outDir/src/bug.d.ts]
export const bug: W.Wrap<{
n: B.Box<number>;
}>;
export const something: 1;
import * as B from "./box.js";
import * as W from "./wrap.js";
//// [/src/project/outDir/src/bug.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.something = exports.bug = void 0;
var B = require("./box.js");
var W = require("./wrap.js");
/**
* @template {object} C
* @param {C} source
* @returns {W.Wrap<C>}
*/
var wrap = function (source) {
throw source;
};
/**
* @returns {B.Box<number>}
*/
var box = function (n) {
if (n === void 0) { n = 0; }
return ({ unbox: function () { return n; } });
};
exports.bug = wrap({ n: box(1) });
exports.something = 1;
//// [/src/project/outDir/tsconfig.tsbuildinfo]
{"program":{"fileNames":["../../../lib/lib.d.ts","../src/box.ts","../src/wrap.ts","../src/bug.js"],"fileInfos":[{"version":"3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true},{"version":"-14267342128-export interface Box<T> {\n unbox(): T\n}\n","signature":"-15554117365-export interface Box<T> {\n unbox(): T;\n}\n"},{"version":"-7208318765-export type Wrap<C> = {\n [K in keyof C]: { wrapped: C[K] }\n}\n","signature":"-7604652776-export type Wrap<C> = {\n [K in keyof C]: {\n wrapped: C[K];\n };\n};\n"},{"version":"-25729561895-import * as B from \"./box.js\"\nimport * as W from \"./wrap.js\"\n\n/**\n * @template {object} C\n * @param {C} source\n * @returns {W.Wrap<C>}\n */\nconst wrap = source => {\nthrow source\n}\n\n/**\n * @returns {B.Box<number>}\n */\nconst box = (n = 0) => ({ unbox: () => n })\n\nexport const bug = wrap({ n: box(1) });\nexport const something = 1;","signature":"-7681488146-export const bug: W.Wrap<{\n n: B.Box<number>;\n}>;\nexport const something: 1;\nimport * as B from \"./box.js\";\nimport * as W from \"./wrap.js\";\n"}],"root":[[2,4]],"options":{"checkJs":true,"composite":true,"outDir":"./"},"fileIdsList":[[2,3]],"referencedMap":[[4,1]],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[1,2,4,3],"latestChangedDtsFile":"./src/bug.d.ts"},"version":"FakeTSVersion"}
//// [/src/project/outDir/tsconfig.tsbuildinfo.readable.baseline.txt]
{
"program": {
"fileNames": [
"../../../lib/lib.d.ts",
"../src/box.ts",
"../src/wrap.ts",
"../src/bug.js"
],
"fileNamesList": [
[
"../src/box.ts",
"../src/wrap.ts"
]
],
"fileInfos": {
"../../../lib/lib.d.ts": {
"original": {
"version": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"affectsGlobalScope": true
},
"version": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"signature": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"affectsGlobalScope": true
},
"../src/box.ts": {
"original": {
"version": "-14267342128-export interface Box<T> {\n unbox(): T\n}\n",
"signature": "-15554117365-export interface Box<T> {\n unbox(): T;\n}\n"
},
"version": "-14267342128-export interface Box<T> {\n unbox(): T\n}\n",
"signature": "-15554117365-export interface Box<T> {\n unbox(): T;\n}\n"
},
"../src/wrap.ts": {
"original": {
"version": "-7208318765-export type Wrap<C> = {\n [K in keyof C]: { wrapped: C[K] }\n}\n",
"signature": "-7604652776-export type Wrap<C> = {\n [K in keyof C]: {\n wrapped: C[K];\n };\n};\n"
},
"version": "-7208318765-export type Wrap<C> = {\n [K in keyof C]: { wrapped: C[K] }\n}\n",
"signature": "-7604652776-export type Wrap<C> = {\n [K in keyof C]: {\n wrapped: C[K];\n };\n};\n"
},
"../src/bug.js": {
"original": {
"version": "-25729561895-import * as B from \"./box.js\"\nimport * as W from \"./wrap.js\"\n\n/**\n * @template {object} C\n * @param {C} source\n * @returns {W.Wrap<C>}\n */\nconst wrap = source => {\nthrow source\n}\n\n/**\n * @returns {B.Box<number>}\n */\nconst box = (n = 0) => ({ unbox: () => n })\n\nexport const bug = wrap({ n: box(1) });\nexport const something = 1;",
"signature": "-7681488146-export const bug: W.Wrap<{\n n: B.Box<number>;\n}>;\nexport const something: 1;\nimport * as B from \"./box.js\";\nimport * as W from \"./wrap.js\";\n"
},
"version": "-25729561895-import * as B from \"./box.js\"\nimport * as W from \"./wrap.js\"\n\n/**\n * @template {object} C\n * @param {C} source\n * @returns {W.Wrap<C>}\n */\nconst wrap = source => {\nthrow source\n}\n\n/**\n * @returns {B.Box<number>}\n */\nconst box = (n = 0) => ({ unbox: () => n })\n\nexport const bug = wrap({ n: box(1) });\nexport const something = 1;",
"signature": "-7681488146-export const bug: W.Wrap<{\n n: B.Box<number>;\n}>;\nexport const something: 1;\nimport * as B from \"./box.js\";\nimport * as W from \"./wrap.js\";\n"
}
},
"root": [
[
[
2,
4
],
[
"../src/box.ts",
"../src/wrap.ts",
"../src/bug.js"
]
]
],
"options": {
"checkJs": true,
"composite": true,
"outDir": "./"
},
"referencedMap": {
"../src/bug.js": [
"../src/box.ts",
"../src/wrap.ts"
]
},
"exportedModulesMap": {},
"semanticDiagnosticsPerFile": [
"../../../lib/lib.d.ts",
"../src/box.ts",
"../src/bug.js",
"../src/wrap.ts"
],
"latestChangedDtsFile": "./src/bug.d.ts"
},
"version": "FakeTSVersion",
"size": 1753
}