From f476065c6e47901386cf2f35bb0763e4446462d0 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 29 Nov 2022 11:56:58 -0500 Subject: [PATCH] Don't add excess properties to type nodes in typeToTypeNode --- src/compiler/binder.ts | 4 ++-- src/compiler/checker.ts | 10 +++------- src/compiler/factory/nodeFactory.ts | 20 ++------------------ src/compiler/parser.ts | 2 +- src/compiler/types.ts | 9 ++++++++- 5 files changed, 16 insertions(+), 29 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 4d785b218fcbb..7ce19bc264fb8 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2348,8 +2348,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { const saveCurrentFlow = currentFlow; for (const typeAlias of delayedTypeAliases) { const host = typeAlias.parent.parent; - container = findAncestor(host.parent, n => !!(getContainerFlags(n) & ContainerFlags.IsContainer)) as IsContainer | undefined || file; - blockScopeContainer = getEnclosingBlockScopeContainer(host) as IsBlockScopedContainer | undefined || file; + container = (findAncestor(host.parent, n => !!(getContainerFlags(n) & ContainerFlags.IsContainer)) as IsContainer | undefined) || file; + blockScopeContainer = (getEnclosingBlockScopeContainer(host) as IsBlockScopedContainer | undefined) || file; currentFlow = initFlowNode({ flags: FlowFlags.Start }); parent = typeAlias; bind(typeAlias.typeExpression); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ba0b63d761775..5857bd1ea94e5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -57,8 +57,8 @@ import { canHaveJSDoc, canHaveLocals, canHaveModifiers, - canUsePropertyAccess, canHaveSymbol, + canUsePropertyAccess, cartesianProduct, CaseBlock, CaseClause, @@ -6589,7 +6589,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { context.truncating = true; } context.approximateLength += cachedResult.addedLength; - return deepCloneOrReuseNode(cachedResult) as TypeNode as T; + return deepCloneOrReuseNode(cachedResult.node) as T; } let depth: number | undefined; @@ -6605,11 +6605,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { 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}); + links?.serializedTypes?.set(key, { node: result, truncating: context.truncating, addedLength }); } context.visitedTypes.delete(typeId); if (id) { diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 86540855462af..231a4e13f2e42 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -2316,9 +2316,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseDeclaration(SyntaxKind.TypeLiteral); node.members = createNodeArray(members); node.transformFlags = TransformFlags.ContainsTypeScript; - - // node.locals = undefined; // initialized by binder (LocalsContainer) - // node.nextContainer = undefined; // initialized by binder (LocalsContainer) return node; } @@ -2746,8 +2743,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.jsDocCache = undefined; // initialized by parser (JsDocContainer) - // node.locals = undefined; // initialized by binder (LocalsContainer) - // node.nextContainer = undefined; // initialized by binder (LocalsContainer) return node; } @@ -3582,8 +3577,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.jsDocCache = undefined; // initialized by parser (JsDocContainer) - // node.locals = undefined; // initialized by binder (LocalsContainer) - // node.nextContainer = undefined; // initialized by binder (LocalsContainer) return node; } @@ -4370,8 +4363,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.jsDocCache = undefined; // initialized by parser (JsDocContainer) - // node.locals = undefined; // initialized by binder (LocalsContainer) - // node.nextContainer = undefined; // initialized by binder (LocalsContainer) return node; } @@ -4412,8 +4403,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.illegalDecorators = undefined; // initialized by parser for grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.jsDocCache = undefined; // initialized by parser (JsDocContainer) - // node.locals = undefined; // initialized by binder (LocalsContainer) - // node.nextContainer = undefined; // initialized by binder (LocalsContainer) return node; } @@ -4507,8 +4496,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.illegalDecorators = undefined; // initialized by parser for grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.jsDocCache = undefined; // initialized by parser (JsDocContainer) - // node.locals = undefined; // initialized by binder (LocalsContainer) - // node.nextContainer = undefined; // initialized by binder (LocalsContainer) return node; } @@ -5139,8 +5126,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseDeclaration(SyntaxKind.JSDocTypeLiteral); node.jsDocPropertyTags = asNodeArray(propertyTags); node.isArrayType = isArrayType; - // node.locals = undefined; // initialized by binder (LocalsContainer) - // node.nextContainer = undefined; // initialized by binder (LocalsContainer) return node; } @@ -5735,8 +5720,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags |= propagateChildrenFlags(node.properties) | TransformFlags.ContainsJsx; - // node.locals = undefined; // initialized by binder (LocalsContainer) - // node.nextContainer = undefined; // initialized by binder (LocalsContainer) return node; } @@ -6094,7 +6077,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } function cloneSourceFileWorker(source: SourceFile) { - // TODO: explicit property assignments instead of for..in + // TODO: This mechanism for cloning results in megamorphic property reads and writes. In future perf-related + // work, we should consider switching explicit property assignments instead of using `for..in`. const node = baseFactory.createBaseSourceFileNode(SyntaxKind.SourceFile) as Mutable; node.flags |= source.flags & ~NodeFlags.Synthesized; for (const p in source) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index ac97d7d7760fc..1e24154f28c6e 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1578,7 +1578,7 @@ namespace Parser { // Prime the scanner. nextToken(); const pos = getNodePos(); - let statements, endOfFileToken: EndOfFileToken; + let statements, endOfFileToken; if (token() === SyntaxKind.EndOfFileToken) { statements = createNodeArray([], pos, pos); endOfFileToken = parseTokenNode(); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d15bf6610df1d..adb89da3d7d55 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5944,12 +5944,19 @@ export interface NodeLinks { isExhaustive?: boolean | 0; // Is node an exhaustive switch statement (0 indicates in-process resolution) 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?: Map; // Collection of types serialized at this location + serializedTypes?: Map; // Collection of types serialized at this location contextualType?: Type; // Used to temporarily assign a contextual type during overload resolution inferenceContext?: InferenceContext; // Inference context for contextual type } +/** @internal */ +export interface SerializedTypeEntry { + node: TypeNode; + truncating?: boolean; + addedLength: number; +} + export const enum TypeFlags { Any = 1 << 0, Unknown = 1 << 1,