Skip to content

Commit

Permalink
Add node result caching internal to typeToTypeNodeHelper
Browse files Browse the repository at this point in the history
  • Loading branch information
weswigham committed May 7, 2021
1 parent 60be8f1 commit 52499b1
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 15 deletions.
81 changes: 75 additions & 6 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4487,7 +4487,7 @@ namespace ts {
enclosingDeclaration,
flags: flags || NodeBuilderFlags.None,
// If no full tracker is provided, fake up a dummy one with a basic limited-functionality moduleResolverHost
tracker: tracker && tracker.trackSymbol ? tracker : { trackSymbol: noop, moduleResolverHost: flags! & NodeBuilderFlags.DoNotIncludeSymbolChain ? {
tracker: tracker && tracker.trackSymbol ? tracker : { trackSymbol: () => false, moduleResolverHost: flags! & NodeBuilderFlags.DoNotIncludeSymbolChain ? {
getCommonSourceDirectory: !!(host as Program).getCommonSourceDirectory ? () => (host as Program).getCommonSourceDirectory() : () => "",
getSourceFiles: () => host.getSourceFiles(),
getCurrentDirectory: () => host.getCurrentDirectory(),
Expand All @@ -4500,18 +4500,50 @@ namespace ts {
getFileIncludeReasons: () => host.getFileIncludeReasons(),
} : undefined },
encounteredError: false,
reportedDiagnostic: false,
visitedTypes: undefined,
symbolDepth: undefined,
inferTypeParameters: undefined,
approximateLength: 0
};
context.tracker = wrapSymbolTrackerToReportForContext(context, context.tracker);
const resultingNode = cb(context);
if (context.truncating && context.flags & NodeBuilderFlags.NoTruncation) {
context.tracker?.reportTruncationError?.();
}
return context.encounteredError ? undefined : resultingNode;
}

function wrapSymbolTrackerToReportForContext(context: NodeBuilderContext, tracker: SymbolTracker): SymbolTracker {
const oldTrackSymbol = tracker.trackSymbol;
return {
...tracker,
reportCyclicStructureError: wrapReportedDiagnostic(tracker.reportCyclicStructureError),
reportInaccessibleThisError: wrapReportedDiagnostic(tracker.reportInaccessibleThisError),
reportInaccessibleUniqueSymbolError: wrapReportedDiagnostic(tracker.reportInaccessibleUniqueSymbolError),
reportLikelyUnsafeImportRequiredError: wrapReportedDiagnostic(tracker.reportLikelyUnsafeImportRequiredError),
reportNonlocalAugmentation: wrapReportedDiagnostic(tracker.reportNonlocalAugmentation),
reportPrivateInBaseOfClassExpression: wrapReportedDiagnostic(tracker.reportPrivateInBaseOfClassExpression),
trackSymbol: oldTrackSymbol && ((...args) => {
const result = oldTrackSymbol(...args);
if (result) {
context.reportedDiagnostic = true;
}
return result;
}),
};

function wrapReportedDiagnostic<T extends (...args: any[]) => any>(method: T | undefined): T | undefined {
if (!method) {
return method;
}
return (((...args) => {
context.reportedDiagnostic = true;
return method(...args);
}) as T);
}
}

function checkTruncationLength(context: NodeBuilderContext): boolean {
if (context.truncating) return context.truncating;
return context.truncating = context.approximateLength > ((context.flags & NodeBuilderFlags.NoTruncation) ? noTruncationMaximumTruncationLength : defaultMaximumTruncationLength);
Expand Down Expand Up @@ -4838,7 +4870,7 @@ namespace ts {
}
}

function visitAndTransformType<T>(type: Type, transform: (type: Type) => T) {
function visitAndTransformType<T extends TypeNode>(type: Type, transform: (type: Type) => T) {
const typeId = type.id;
const isConstructorObject = getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class;
const id = getObjectFlags(type) & ObjectFlags.Reference && (<TypeReference>type).node ? "N" + getNodeId((<TypeReference>type).node!) :
Expand All @@ -4853,6 +4885,20 @@ namespace ts {
context.symbolDepth = new Map();
}

const links = context.enclosingDeclaration && getNodeLinks(context.enclosingDeclaration);
const key = `${getTypeId(type)}|${context.flags}`;
if (links) {
links.serializedTypes ||= new Map();
}
const cachedResult = links?.serializedTypes?.get(key);
if (cachedResult) {
if (cachedResult.truncating) {
context.truncating = true;
}
context.approximateLength += cachedResult.addedLength;
return deepCloneOrReuseNode(cachedResult) as TypeNode as T;
}

let depth: number | undefined;
if (id) {
depth = context.symbolDepth!.get(id) || 0;
Expand All @@ -4862,12 +4908,28 @@ namespace ts {
context.symbolDepth!.set(id, depth + 1);
}
context.visitedTypes.add(typeId);
const startLength = context.approximateLength;
const result = transform(type);
const addedLength = context.approximateLength - startLength;
if (!context.reportedDiagnostic && !context.encounteredError) {
if (context.truncating) {
(result as any).truncating = true;
}
(result as any).addedLength = addedLength;
links?.serializedTypes?.set(key, result as TypeNode as TypeNode & {truncating?: boolean, addedLength: number});
}
context.visitedTypes.delete(typeId);
if (id) {
context.symbolDepth!.set(id, depth!);
}
return result;

function deepCloneOrReuseNode(node: Node): Node {
if (!nodeIsSynthesized(node) && getParseTreeNode(node) === node) {
return node;
}
return setTextRange(factory.cloneNode(visitEachChild(node, deepCloneOrReuseNode, nullTransformationContext)), node);
}
}

function createTypeNodeFromObjectType(type: ObjectType): TypeNode {
Expand Down Expand Up @@ -5998,6 +6060,7 @@ namespace ts {
if (initial.typeParameterSymbolList) {
initial.typeParameterSymbolList = new Set(initial.typeParameterSymbolList);
}
initial.tracker = wrapSymbolTrackerToReportForContext(initial, initial.tracker);
return initial;
}

Expand Down Expand Up @@ -6289,11 +6352,13 @@ namespace ts {
}
}
else if (oldcontext.tracker && oldcontext.tracker.trackSymbol) {
oldcontext.tracker.trackSymbol(sym, decl, meaning);
return oldcontext.tracker.trackSymbol(sym, decl, meaning);
}
}
}
return false;
},
},
};
context.tracker = wrapSymbolTrackerToReportForContext(context, context.tracker);
forEachEntry(symbolTable, (symbol, name) => {
const baseName = unescapeLeadingUnderscores(name);
void getInternalSymbolName(symbol, baseName); // Called to cache values into `usedSymbolNames` and `remappedSymbolNames`
Expand Down Expand Up @@ -6513,6 +6578,9 @@ namespace ts {
const oldContext = context;
context = cloneNodeBuilderContext(context);
const result = serializeSymbolWorker(symbol, isPrivate, propertyAsAlias);
if (context.reportedDiagnostic) {
oldcontext.reportedDiagnostic = context.reportedDiagnostic; // hoist diagnostic result into outer context
}
context = oldContext;
return result;
}
Expand Down Expand Up @@ -7286,7 +7354,7 @@ namespace ts {
// a visibility error here (as they're not visible within any scope), but we want to hoist them
// into the containing scope anyway, so we want to skip the visibility checks.
const oldTrack = context.tracker.trackSymbol;
context.tracker.trackSymbol = noop;
context.tracker.trackSymbol = () => false;
if (isExportAssignmentCompatibleSymbolName) {
results.push(factory.createExportAssignment(
/*decorators*/ undefined,
Expand Down Expand Up @@ -7742,6 +7810,7 @@ namespace ts {

// State
encounteredError: boolean;
reportedDiagnostic: boolean;
visitedTypes: Set<number> | undefined;
symbolDepth: ESMap<string, number> | undefined;
inferTypeParameters: TypeParameter[] | undefined;
Expand Down
7 changes: 5 additions & 2 deletions src/compiler/transformers/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,10 @@ namespace ts {
symbolAccessibilityResult.errorSymbolName,
symbolAccessibilityResult.errorModuleName));
}
return true;
}
}
return false;
}

function trackExternalModuleSymbolOfImportTypeNode(symbol: Symbol) {
Expand All @@ -156,9 +158,10 @@ namespace ts {
}

function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
if (symbol.flags & SymbolFlags.TypeParameter) return;
handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning, /*shouldComputeAliasesToMakeVisible*/ true));
if (symbol.flags & SymbolFlags.TypeParameter) return false;
const issuedDiagnostic = handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning, /*shouldComputeAliasesToMakeVisible*/ true));
recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForSymbol(symbol, meaning));
return issuedDiagnostic;
}

function reportPrivateInBaseOfClassExpression(propertyName: string) {
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4987,6 +4987,7 @@ namespace ts {
isExhaustive?: boolean; // Is node an exhaustive switch statement
skipDirectInference?: true; // Flag set by the API `getContextualType` call on a node when `Completions` is passed to force the checker to skip making inferences to a node's type
declarationRequiresScopeChange?: boolean; // Set by `useOuterVariableScopeInParameter` in checker when downlevel emit would change the name resolution scope inside of a parameter.
serializedTypes?: ESMap<string, TypeNode & {truncating?: boolean, addedLength: number}>; // Collection of types serialized at this location
}

export const enum TypeFlags {
Expand Down Expand Up @@ -8110,7 +8111,7 @@ namespace ts {
// Called when the symbol writer encounters a symbol to write. Currently only used by the
// declaration emitter to help determine if it should patch up the final declaration file
// with import statements it previously saw (but chose not to emit).
trackSymbol?(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags): void;
trackSymbol?(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags): boolean;
reportInaccessibleThisError?(): void;
reportPrivateInBaseOfClassExpression?(propertyName: string): void;
reportInaccessibleUniqueSymbolError?(): void;
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ namespace ts {
increaseIndent: noop,
decreaseIndent: noop,
clear: () => str = "",
trackSymbol: noop,
trackSymbol: () => false,
reportInaccessibleThisError: noop,
reportInaccessibleUniqueSymbolError: noop,
reportPrivateInBaseOfClassExpression: noop,
Expand Down Expand Up @@ -4023,7 +4023,7 @@ namespace ts {
reportInaccessibleThisError: noop,
reportPrivateInBaseOfClassExpression: noop,
reportInaccessibleUniqueSymbolError: noop,
trackSymbol: noop,
trackSymbol: () => false,
writeKeyword: write,
writeOperator: write,
writeParameter: write,
Expand Down
2 changes: 1 addition & 1 deletion src/services/codefixes/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace ts.codefix {

export function getNoopSymbolTrackerWithResolver(context: TypeConstructionContext): SymbolTracker {
return {
trackSymbol: noop,
trackSymbol: () => false,
moduleResolverHost: getModuleSpecifierResolverHost(context.program, context.host),
};
}
Expand Down
3 changes: 2 additions & 1 deletion src/services/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2093,7 +2093,7 @@ namespace ts {
increaseIndent: () => { indent++; },
decreaseIndent: () => { indent--; },
clear: resetWriter,
trackSymbol: noop,
trackSymbol: () => false,
reportInaccessibleThisError: noop,
reportInaccessibleUniqueSymbolError: noop,
reportPrivateInBaseOfClassExpression: noop,
Expand Down Expand Up @@ -2619,6 +2619,7 @@ namespace ts {
const res = checker.typeToTypeNode(type, enclosingScope, NodeBuilderFlags.NoTruncation, {
trackSymbol: (symbol, declaration, meaning) => {
typeIsAccessible = typeIsAccessible && checker.isSymbolAccessible(symbol, declaration, meaning, /*shouldComputeAliasToMarkVisible*/ false).accessibility === SymbolAccessibility.Accessible;
return !typeIsAccessible;
},
reportInaccessibleThisError: notAccessible,
reportPrivateInBaseOfClassExpression: notAccessible,
Expand Down
Loading

0 comments on commit 52499b1

Please sign in to comment.