@@ -6623,8 +6623,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
66236623 }
66246624 if (
66256625 context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams &&
6626- type.flags & TypeFlags.TypeParameter &&
6627- !isTypeSymbolAccessible(type.symbol, context.enclosingDeclaration)
6626+ type.flags & TypeFlags.TypeParameter
66286627 ) {
66296628 const name = typeParameterToName(type, context);
66306629 context.approximateLength += idText(name).length;
@@ -7527,7 +7526,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
75277526 && signature.declaration
75287527 && signature.declaration !== context.enclosingDeclaration
75297528 && !isInJSFile(signature.declaration)
7530- && some(expandedParams)
7529+ && ( some(expandedParams) || some(signature.typeParameters) )
75317530 ) {
75327531 // As a performance optimization, reuse the same fake scope within this chain.
75337532 // This is especially needed when we are working on an excessively deep type;
@@ -7545,32 +7544,64 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
75457544 // Note that we only check the most immediate enclosingDeclaration; the only place we
75467545 // could potentially add another fake scope into the chain is right here, so we don't
75477546 // traverse all ancestors.
7548- const existingFakeScope = getNodeLinks(context.enclosingDeclaration).fakeScopeForSignatureDeclaration ? context.enclosingDeclaration : undefined;
7549- Debug.assertOptionalNode(existingFakeScope, isBlock);
7547+ pushFakeScope(
7548+ "params",
7549+ add => {
7550+ for (const param of expandedParams) {
7551+ add(param.escapedName, param);
7552+ }
7553+ },
7554+ );
75507555
7551- const locals = existingFakeScope?.locals ?? createSymbolTable();
7556+ if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams) {
7557+ // TODO(jakebailey): should this instead be done before walking type parameters?
7558+ pushFakeScope(
7559+ "typeParams",
7560+ add => {
7561+ for (const typeParam of signature.typeParameters ?? emptyArray) {
7562+ const typeParamName = typeParameterToName(typeParam, context).escapedText;
7563+ add(typeParamName, typeParam.symbol);
7564+ }
7565+ },
7566+ );
7567+ }
75527568
7553- let newLocals: __String[] | undefined;
7554- for (const param of expandedParams) {
7555- if (!locals.has(param.escapedName)) {
7556- newLocals = append(newLocals, param.escapedName);
7557- locals.set(param.escapedName, param);
7569+ function pushFakeScope(kind: "params" | "typeParams", addAll: (addSymbol: (name: __String, symbol: Symbol) => void) => void) {
7570+ // We only ever need to look two declarations upward.
7571+ Debug.assert(context.enclosingDeclaration);
7572+ let existingFakeScope: Node | undefined;
7573+ if (getNodeLinks(context.enclosingDeclaration).fakeScopeForSignatureDeclaration === kind) {
7574+ existingFakeScope = context.enclosingDeclaration;
75587575 }
7559- }
7576+ else if (context.enclosingDeclaration.parent && getNodeLinks(context.enclosingDeclaration.parent).fakeScopeForSignatureDeclaration === kind) {
7577+ existingFakeScope = context.enclosingDeclaration.parent;
7578+ }
7579+ Debug.assertOptionalNode(existingFakeScope, isBlock);
75607580
7561- if (newLocals) {
7562- function removeNewLocals() {
7581+ const locals = existingFakeScope?.locals ?? createSymbolTable();
7582+ let newLocals: __String[] | undefined;
7583+ addAll((name, symbol) => {
7584+ if (!locals.has(name)) {
7585+ newLocals = append(newLocals, name);
7586+ locals.set(name, symbol);
7587+ }
7588+ });
7589+ if (!newLocals) return;
7590+
7591+ const oldCleanup = cleanup;
7592+ function undo() {
75637593 forEach(newLocals, s => locals.delete(s));
7594+ oldCleanup?.();
75647595 }
75657596
75667597 if (existingFakeScope) {
7567- cleanup = removeNewLocals ;
7598+ cleanup = undo ;
75687599 }
75697600 else {
75707601 // Use a Block for this; the type of the node doesn't matter so long as it
75717602 // has locals, and this is cheaper/easier than using a function-ish Node.
75727603 const fakeScope = parseNodeFactory.createBlock(emptyArray);
7573- getNodeLinks(fakeScope).fakeScopeForSignatureDeclaration = true ;
7604+ getNodeLinks(fakeScope).fakeScopeForSignatureDeclaration = kind ;
75747605 fakeScope.locals = locals;
75757606
75767607 const saveEnclosingDeclaration = context.enclosingDeclaration;
@@ -7579,7 +7610,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
75797610
75807611 cleanup = () => {
75817612 context.enclosingDeclaration = saveEnclosingDeclaration;
7582- removeNewLocals ();
7613+ undo ();
75837614 };
75847615 }
75857616 }
@@ -8127,13 +8158,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
81278158 }
81288159 }
81298160
8130- function typeParameterShadowsNameInScope (escapedName: __String, context: NodeBuilderContext, type: TypeParameter) {
8161+ function typeParameterShadowsOtherTypeParameterInScope (escapedName: __String, context: NodeBuilderContext, type: TypeParameter) {
81318162 const result = resolveName(context.enclosingDeclaration, escapedName, SymbolFlags.Type, /*nameNotFoundMessage*/ undefined, escapedName, /*isUse*/ false);
8132- if (result) {
8133- if (result.flags & SymbolFlags.TypeParameter && result === type.symbol) {
8134- return false;
8135- }
8136- return true;
8163+ if (result && result.flags & SymbolFlags.TypeParameter) {
8164+ return result !== type.symbol;
81378165 }
81388166 return false;
81398167 }
@@ -8153,7 +8181,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
81538181 const rawtext = result.escapedText as string;
81548182 let i = context.typeParameterNamesByTextNextNameCount?.get(rawtext) || 0;
81558183 let text = rawtext;
8156- while (context.typeParameterNamesByText?.has(text) || typeParameterShadowsNameInScope (text as __String, context, type)) {
8184+ while (context.typeParameterNamesByText?.has(text) || typeParameterShadowsOtherTypeParameterInScope (text as __String, context, type)) {
81578185 i++;
81588186 text = `${rawtext}_${i}`;
81598187 }
@@ -8166,7 +8194,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
81668194 // `i` we've used thus far, to save work later
81678195 (context.typeParameterNamesByTextNextNameCount ||= new Map()).set(rawtext, i);
81688196 (context.typeParameterNames ||= new Map()).set(getTypeId(type), result);
8169- (context.typeParameterNamesByText ||= new Set()).add(rawtext );
8197+ (context.typeParameterNamesByText ||= new Set()).add(text );
81708198 }
81718199 return result;
81728200 }
@@ -8345,7 +8373,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
83458373 }
83468374
83478375 function getEnclosingDeclarationIgnoringFakeScope(enclosingDeclaration: Node) {
8348- return getNodeLinks(enclosingDeclaration).fakeScopeForSignatureDeclaration ? enclosingDeclaration.parent : enclosingDeclaration;
8376+ while (getNodeLinks(enclosingDeclaration).fakeScopeForSignatureDeclaration) {
8377+ enclosingDeclaration = enclosingDeclaration.parent;
8378+ }
8379+ return enclosingDeclaration;
83498380 }
83508381
83518382 /**
@@ -8425,7 +8456,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
84258456 }
84268457 if (isIdentifier(node)) {
84278458 const type = getDeclaredTypeOfSymbol(sym);
8428- const name = sym.flags & SymbolFlags.TypeParameter && !isTypeSymbolAccessible(type.symbol, context.enclosingDeclaration) ? typeParameterToName(type, context) : factory.cloneNode(node);
8459+ const name = sym.flags & SymbolFlags.TypeParameter ? typeParameterToName(type, context) : factory.cloneNode(node);
84298460 name.symbol = sym; // for quickinfo, which uses identifier symbol information
84308461 return { introducesError, node: setEmitFlags(setOriginalNode(name, node), EmitFlags.NoAsciiEscaping) };
84318462 }
0 commit comments