diff --git a/internal/checker/emitresolver.go b/internal/checker/emitresolver.go index 1a28c3c21e..f5bc7ad854 100644 --- a/internal/checker/emitresolver.go +++ b/internal/checker/emitresolver.go @@ -1078,6 +1078,19 @@ func (r *emitResolver) CreateLateBoundIndexSignatures(emitContext *printer.EmitC return result } +func (r *emitResolver) TrackExistingEntityName(emitContext *printer.EmitContext, node *ast.Node, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node { + original := emitContext.ParseNode(node) + if original == nil { + return node + } + + r.checkerMu.Lock() + defer r.checkerMu.Unlock() + + requestNodeBuilder := NewNodeBuilder(r.checker, emitContext) // TODO: cache per-context + return requestNodeBuilder.TrackExistingEntityName(original, enclosingDeclaration, flags, internalFlags, tracker) +} + func (r *emitResolver) GetEffectiveDeclarationFlags(node *ast.Node, flags ast.ModifierFlags) ast.ModifierFlags { // node = emitContext.ParseNode(node) r.checkerMu.Lock() diff --git a/internal/checker/nodebuilder.go b/internal/checker/nodebuilder.go index bd629596c7..b83baacb16 100644 --- a/internal/checker/nodebuilder.go +++ b/internal/checker/nodebuilder.go @@ -162,6 +162,12 @@ func (b *NodeBuilder) TypeParameterToDeclaration(parameter *Type, enclosingDecla return b.exitContext(b.impl.typeParameterToDeclaration(parameter)) } +// TrackExistingEntityName tracks an existing entity name and returns a potentially renamed version. +func (b *NodeBuilder) TrackExistingEntityName(node *ast.Node, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node { + b.enterContext(enclosingDeclaration, flags, internalFlags, tracker) + return b.exitContext(b.impl.trackExistingEntityName(node)) +} + // TypePredicateToTypePredicateNode implements NodeBuilderInterface. func (b *NodeBuilder) TypePredicateToTypePredicateNode(predicate *TypePredicate, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node { b.enterContext(enclosingDeclaration, flags, internalFlags, tracker) diff --git a/internal/checker/nodebuilderimpl.go b/internal/checker/nodebuilderimpl.go index afdc9494d7..d2558c4d43 100644 --- a/internal/checker/nodebuilderimpl.go +++ b/internal/checker/nodebuilderimpl.go @@ -1346,6 +1346,29 @@ func (b *nodeBuilderImpl) typeParameterToName(typeParameter *Type) *ast.Identifi return result.AsIdentifier() } +func (b *nodeBuilderImpl) trackExistingEntityName(node *ast.Node) *ast.Node { + if node == nil || !ast.IsIdentifier(node) { + return node + } + + // Get the symbol for this identifier + symbol := b.ch.getSymbolOfNode(node) + if symbol == nil { + return node + } + + // If it's a type parameter, use typeParameterToName to get a potentially renamed version + if symbol.Flags&ast.SymbolFlagsTypeParameter != 0 { + typeParam := b.ch.getDeclaredTypeOfSymbol(symbol) + if typeParam != nil { + return b.typeParameterToName(typeParam).AsNode() + } + } + + // For non-type-parameter identifiers, return a clone + return node.Clone(b.f) +} + func (b *nodeBuilderImpl) isMappedTypeHomomorphic(mapped *Type) bool { return b.ch.getHomomorphicTypeVariable(mapped) != nil } diff --git a/internal/printer/emitresolver.go b/internal/printer/emitresolver.go index 156709cf68..b4f85a13c3 100644 --- a/internal/printer/emitresolver.go +++ b/internal/printer/emitresolver.go @@ -65,4 +65,5 @@ type EmitResolver interface { CreateLiteralConstValue(emitContext *EmitContext, node *ast.Node, tracker nodebuilder.SymbolTracker) *ast.Node CreateTypeOfExpression(emitContext *EmitContext, expression *ast.Node, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node CreateLateBoundIndexSignatures(emitContext *EmitContext, container *ast.Node, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) []*ast.Node + TrackExistingEntityName(emitContext *EmitContext, node *ast.Node, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node } diff --git a/internal/transformers/declarations/transform.go b/internal/transformers/declarations/transform.go index 6217557d5f..80e7afedfa 100644 --- a/internal/transformers/declarations/transform.go +++ b/internal/transformers/declarations/transform.go @@ -634,16 +634,39 @@ func (tx *DeclarationTransformer) transformExpressionWithTypeArguments(input *as } func (tx *DeclarationTransformer) transformTypeParameterDeclaration(input *ast.TypeParameterDeclaration) *ast.Node { + // Track the type parameter name to handle shadowing + tpName := tx.resolver.TrackExistingEntityName( + tx.EmitContext(), + input.Name(), + tx.enclosingDeclaration, + declarationEmitNodeBuilderFlags, + declarationEmitInternalNodeBuilderFlags, + tx.tracker, + ) + if isPrivateMethodTypeParameter(tx.host, input) && (input.DefaultType != nil || input.Constraint != nil) { return tx.Factory().UpdateTypeParameterDeclaration( input, input.Modifiers(), - input.Name(), + tpName, nil, nil, ) } - return tx.Visitor().VisitEachChild(input.AsNode()) + + // Visit children to transform constraint and default type + modifiers := tx.Visitor().VisitModifiers(input.Modifiers()) + constraint := tx.Visitor().VisitNode(input.Constraint) + defaultType := tx.Visitor().VisitNode(input.DefaultType) + + // Update the type parameter declaration with the potentially renamed name + return tx.Factory().UpdateTypeParameterDeclaration( + input, + modifiers, + tpName, + constraint, + defaultType, + ) } func (tx *DeclarationTransformer) transformVariableDeclaration(input *ast.VariableDeclaration) *ast.Node {