@@ -6598,8 +6598,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
65986598 }
65996599 if (
66006600 context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams &&
6601- type.flags & TypeFlags.TypeParameter &&
6602- !isTypeSymbolAccessible(type.symbol, context.enclosingDeclaration)
6601+ type.flags & TypeFlags.TypeParameter
66036602 ) {
66046603 const name = typeParameterToName(type, context);
66056604 context.approximateLength += idText(name).length;
@@ -7464,7 +7463,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
74647463 && signature.declaration
74657464 && signature.declaration !== context.enclosingDeclaration
74667465 && !isInJSFile(signature.declaration)
7467- && some(expandedParams)
7466+ && ( some(expandedParams) || some(signature.typeParameters) )
74687467 ) {
74697468 // As a performance optimization, reuse the same fake scope within this chain.
74707469 // This is especially needed when we are working on an excessively deep type;
@@ -7482,32 +7481,64 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
74827481 // Note that we only check the most immediate enclosingDeclaration; the only place we
74837482 // could potentially add another fake scope into the chain is right here, so we don't
74847483 // traverse all ancestors.
7485- const existingFakeScope = getNodeLinks(context.enclosingDeclaration).fakeScopeForSignatureDeclaration ? context.enclosingDeclaration : undefined;
7486- Debug.assertOptionalNode(existingFakeScope, isBlock);
7484+ pushFakeScope(
7485+ "params",
7486+ add => {
7487+ for (const param of expandedParams) {
7488+ add(param.escapedName, param);
7489+ }
7490+ },
7491+ );
74877492
7488- const locals = existingFakeScope?.locals ?? createSymbolTable();
7493+ if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams) {
7494+ // TODO(jakebailey): should this instead be done before walking type parameters?
7495+ pushFakeScope(
7496+ "typeParams",
7497+ add => {
7498+ for (const typeParam of signature.typeParameters ?? emptyArray) {
7499+ const typeParamName = typeParameterToName(typeParam, context).escapedText;
7500+ add(typeParamName, typeParam.symbol);
7501+ }
7502+ },
7503+ );
7504+ }
74897505
7490- let newLocals: __String[] | undefined;
7491- for (const param of expandedParams) {
7492- if (!locals.has(param.escapedName)) {
7493- newLocals = append(newLocals, param.escapedName);
7494- locals.set(param.escapedName, param);
7506+ function pushFakeScope(kind: "params" | "typeParams", addAll: (addSymbol: (name: __String, symbol: Symbol) => void) => void) {
7507+ // We only ever need to look two declarations upward.
7508+ Debug.assert(context.enclosingDeclaration);
7509+ let existingFakeScope: Node | undefined;
7510+ if (getNodeLinks(context.enclosingDeclaration).fakeScopeForSignatureDeclaration === kind) {
7511+ existingFakeScope = context.enclosingDeclaration;
74957512 }
7496- }
7513+ else if (context.enclosingDeclaration.parent && getNodeLinks(context.enclosingDeclaration.parent).fakeScopeForSignatureDeclaration === kind) {
7514+ existingFakeScope = context.enclosingDeclaration.parent;
7515+ }
7516+ Debug.assertOptionalNode(existingFakeScope, isBlock);
74977517
7498- if (newLocals) {
7499- function removeNewLocals() {
7518+ const locals = existingFakeScope?.locals ?? createSymbolTable();
7519+ let newLocals: __String[] | undefined;
7520+ addAll((name, symbol) => {
7521+ if (!locals.has(name)) {
7522+ newLocals = append(newLocals, name);
7523+ locals.set(name, symbol);
7524+ }
7525+ });
7526+ if (!newLocals) return;
7527+
7528+ const oldCleanup = cleanup;
7529+ function undo() {
75007530 forEach(newLocals, s => locals.delete(s));
7531+ oldCleanup?.();
75017532 }
75027533
75037534 if (existingFakeScope) {
7504- cleanup = removeNewLocals ;
7535+ cleanup = undo ;
75057536 }
75067537 else {
75077538 // Use a Block for this; the type of the node doesn't matter so long as it
75087539 // has locals, and this is cheaper/easier than using a function-ish Node.
75097540 const fakeScope = parseNodeFactory.createBlock(emptyArray);
7510- getNodeLinks(fakeScope).fakeScopeForSignatureDeclaration = true ;
7541+ getNodeLinks(fakeScope).fakeScopeForSignatureDeclaration = kind ;
75117542 fakeScope.locals = locals;
75127543
75137544 const saveEnclosingDeclaration = context.enclosingDeclaration;
@@ -7516,7 +7547,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
75167547
75177548 cleanup = () => {
75187549 context.enclosingDeclaration = saveEnclosingDeclaration;
7519- removeNewLocals ();
7550+ undo ();
75207551 };
75217552 }
75227553 }
@@ -8062,13 +8093,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
80628093 }
80638094 }
80648095
8065- function typeParameterShadowsNameInScope (escapedName: __String, context: NodeBuilderContext, type: TypeParameter) {
8096+ function typeParameterShadowsOtherTypeParameterInScope (escapedName: __String, context: NodeBuilderContext, type: TypeParameter) {
80668097 const result = resolveName(context.enclosingDeclaration, escapedName, SymbolFlags.Type, /*nameNotFoundMessage*/ undefined, escapedName, /*isUse*/ false);
8067- if (result) {
8068- if (result.flags & SymbolFlags.TypeParameter && result === type.symbol) {
8069- return false;
8070- }
8071- return true;
8098+ if (result && result.flags & SymbolFlags.TypeParameter) {
8099+ return result !== type.symbol;
80728100 }
80738101 return false;
80748102 }
@@ -8088,7 +8116,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
80888116 const rawtext = result.escapedText as string;
80898117 let i = context.typeParameterNamesByTextNextNameCount?.get(rawtext) || 0;
80908118 let text = rawtext;
8091- while (context.typeParameterNamesByText?.has(text) || typeParameterShadowsNameInScope (text as __String, context, type)) {
8119+ while (context.typeParameterNamesByText?.has(text) || typeParameterShadowsOtherTypeParameterInScope (text as __String, context, type)) {
80928120 i++;
80938121 text = `${rawtext}_${i}`;
80948122 }
@@ -8101,7 +8129,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
81018129 // `i` we've used thus far, to save work later
81028130 (context.typeParameterNamesByTextNextNameCount ||= new Map()).set(rawtext, i);
81038131 (context.typeParameterNames ||= new Map()).set(getTypeId(type), result);
8104- (context.typeParameterNamesByText ||= new Set()).add(rawtext );
8132+ (context.typeParameterNamesByText ||= new Set()).add(text );
81058133 }
81068134 return result;
81078135 }
@@ -8280,7 +8308,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
82808308 }
82818309
82828310 function getEnclosingDeclarationIgnoringFakeScope(enclosingDeclaration: Node) {
8283- return getNodeLinks(enclosingDeclaration).fakeScopeForSignatureDeclaration ? enclosingDeclaration.parent : enclosingDeclaration;
8311+ while (getNodeLinks(enclosingDeclaration).fakeScopeForSignatureDeclaration) {
8312+ enclosingDeclaration = enclosingDeclaration.parent;
8313+ }
8314+ return enclosingDeclaration;
82848315 }
82858316
82868317 /**
@@ -8360,7 +8391,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
83608391 }
83618392 if (isIdentifier(node)) {
83628393 const type = getDeclaredTypeOfSymbol(sym);
8363- const name = sym.flags & SymbolFlags.TypeParameter && !isTypeSymbolAccessible(type.symbol, context.enclosingDeclaration) ? typeParameterToName(type, context) : factory.cloneNode(node);
8394+ const name = sym.flags & SymbolFlags.TypeParameter ? typeParameterToName(type, context) : factory.cloneNode(node);
83648395 name.symbol = sym; // for quickinfo, which uses identifier symbol information
83658396 return { introducesError, node: setEmitFlags(setOriginalNode(name, node), EmitFlags.NoAsciiEscaping) };
83668397 }
0 commit comments