From c04b6a1e5b1a1d2cecac13ebb7dbf904206c8112 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 5 Apr 2026 10:54:44 -0400 Subject: [PATCH 1/8] Reparse CJS export assignments only when not shadowed by locals --- internal/ast/utilities.go | 2 +- internal/binder/binder.go | 2 +- internal/parser/parser.go | 55 ++++++++++++++++++++++++++++++++++++- internal/parser/reparser.go | 18 ++++++++---- 4 files changed, 68 insertions(+), 9 deletions(-) diff --git a/internal/ast/utilities.go b/internal/ast/utilities.go index 686d0932109..d2ec4d0f385 100644 --- a/internal/ast/utilities.go +++ b/internal/ast/utilities.go @@ -1477,7 +1477,7 @@ func GetNonAssignedNameOfDeclaration(declaration *Node) *Node { switch declaration.Kind { case KindBinaryExpression, KindCallExpression: switch GetAssignmentDeclarationKind(declaration) { - case JSDeclarationKindProperty, JSDeclarationKindThisProperty, JSDeclarationKindExportsProperty: + case JSDeclarationKindProperty, JSDeclarationKindThisProperty, JSDeclarationKindExportsProperty, JSDeclarationKindModuleExports: left := declaration.AsBinaryExpression().Left if name := GetElementOrPropertyAccessName(left); name != nil { return name diff --git a/internal/binder/binder.go b/internal/binder/binder.go index 7fddd97b36d..28a69a3c9d5 100644 --- a/internal/binder/binder.go +++ b/internal/binder/binder.go @@ -629,7 +629,7 @@ func (b *Binder) bind(node *ast.Node) bool { } case ast.KindBinaryExpression: switch ast.GetAssignmentDeclarationKind(node) { - case ast.JSDeclarationKindProperty: + case ast.JSDeclarationKindModuleExports, ast.JSDeclarationKindExportsProperty, ast.JSDeclarationKindProperty: b.bindExpandoPropertyAssignment(node) case ast.JSDeclarationKindThisProperty: b.bindThisPropertyAssignment(node) diff --git a/internal/parser/parser.go b/internal/parser/parser.go index 2689da488f3..c70b92aeba0 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -61,6 +61,13 @@ const ( jsdocScannerInfoHasSeeOrLink ) +type ShadowFlags int32 + +const ( + ShadowFlagsModule = 1 << iota // `module` identifier is shadowed + ShadowFlagsExports // `exports` identifier is shadowed +) + type Parser struct { scanner *scanner.Scanner factory ast.NodeFactory @@ -78,6 +85,7 @@ type Parser struct { sourceFlags ast.NodeFlags contextFlags ast.NodeFlags parsingContexts ParsingContexts + shadowFlags ShadowFlags statementHasAwaitIdentifier bool hasDeprecatedTag bool hasParseError bool @@ -1209,7 +1217,9 @@ func (p *Parser) parseBlock(ignoreMissingOpenBrace bool, diagnosticMessage *diag multiline := false if openBraceParsed || ignoreMissingOpenBrace { multiline = p.hasPrecedingLineBreak() + saveShadowFlags := p.shadowFlags statements := p.parseList(PCBlockStatements, (*Parser).parseStatement) + p.shadowFlags = saveShadowFlags p.parseExpectedMatchingBrackets(ast.KindOpenBraceToken, ast.KindCloseBraceToken, openBraceParsed, openBracePosition) result := p.finishNode(p.factory.NewBlock(statements, multiline), pos) p.withJSDoc(result, jsdoc) @@ -1288,6 +1298,7 @@ func (p *Parser) parseWhileStatement() *ast.Node { func (p *Parser) parseForOrForInOrForOfStatement() *ast.Node { pos := p.nodePos() jsdoc := p.jsdocScannerInfo() + saveShadowFlags := p.shadowFlags p.parseExpected(ast.KindForKeyword) awaitToken := p.parseOptionalToken(ast.KindAwaitKeyword) p.parseExpected(ast.KindOpenParenToken) @@ -1326,6 +1337,7 @@ func (p *Parser) parseForOrForInOrForOfStatement() *ast.Node { p.parseExpected(ast.KindCloseParenToken) result = p.factory.NewForStatement(initializer, condition, incrementor, p.parseStatement()) } + p.shadowFlags = saveShadowFlags p.finishNode(result, pos) p.withJSDoc(result, jsdoc) return result @@ -1491,6 +1503,7 @@ func (p *Parser) parseTryStatement() *ast.Node { func (p *Parser) parseCatchClause() *ast.Node { pos := p.nodePos() + saveShadowFlags := p.shadowFlags p.parseExpected(ast.KindCatchKeyword) var variableDeclaration *ast.Node if p.parseOptional(ast.KindOpenParenToken) { @@ -1498,6 +1511,7 @@ func (p *Parser) parseCatchClause() *ast.Node { p.parseExpected(ast.KindCloseParenToken) } block := p.parseBlock(false /*ignoreMissingOpenBrace*/, nil) + p.shadowFlags = saveShadowFlags result := p.finishNode(p.factory.NewCatchClause(variableDeclaration, block), pos) return result } @@ -1639,7 +1653,20 @@ func (p *Parser) parseIdentifierOrPatternWithDiagnostic(privateIdentifierDiagnos if p.token == ast.KindOpenBraceToken { return p.parseObjectBindingPattern() } - return p.parseBindingIdentifierWithDiagnostic(privateIdentifierDiagnosticMessage) + id := p.parseBindingIdentifierWithDiagnostic(privateIdentifierDiagnosticMessage) + p.updateShadowFlags(id) + return id +} + +func (p *Parser) updateShadowFlags(name *ast.Node) { + if p.isJavaScript() && name != nil { + if ast.IsModuleIdentifier(name) { + p.shadowFlags |= ShadowFlagsModule + } + if ast.IsExportsIdentifier(name) { + p.shadowFlags |= ShadowFlagsExports + } + } } func (p *Parser) parseArrayBindingPattern() *ast.Node { @@ -1687,6 +1714,7 @@ func (p *Parser) parseObjectBindingElement() *ast.Node { if tokenIsIdentifier && p.token != ast.KindColonToken { name = propertyName propertyName = nil + p.updateShadowFlags(name) } else { p.parseExpected(ast.KindColonToken) name = p.parseIdentifierOrPattern() @@ -1716,16 +1744,19 @@ func (p *Parser) parseFunctionDeclaration(pos int, jsdoc jsdocScannerInfo, modif var name *ast.Node if modifiers == nil || modifiers.ModifierFlags&ast.ModifierFlagsDefault == 0 || p.isBindingIdentifier() { name = p.parseBindingIdentifier() + p.updateShadowFlags(name) } signatureFlags := core.IfElse(asteriskToken != nil, ParseFlagsYield, ParseFlagsNone) | core.IfElse(modifiers != nil && modifiers.ModifierFlags&ast.ModifierFlagsAsync != 0, ParseFlagsAwait, ParseFlagsNone) typeParameters := p.parseTypeParameters() saveContextFlags := p.contextFlags + saveShadowFlags := p.shadowFlags if modifiers != nil && modifiers.ModifierFlags&ast.ModifierFlagsExport != 0 { p.setContextFlags(ast.NodeFlagsAwaitContext, true) } parameters := p.parseParameters(signatureFlags) returnType := p.parseReturnType(ast.KindColonToken, false /*isType*/) body := p.parseFunctionBlockOrSemicolon(signatureFlags, diagnostics.X_or_expected) + p.shadowFlags = saveShadowFlags p.contextFlags = saveContextFlags result := p.finishNode(p.factory.NewFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, returnType, nil /*fullSignature*/, body), pos) p.withJSDoc(result, jsdoc) @@ -1747,6 +1778,9 @@ func (p *Parser) parseClassDeclarationOrExpression(pos int, jsdoc jsdocScannerIn p.parseExpected(ast.KindClassKeyword) // We don't parse the name here in await context, instead we will report a grammar error in the checker. name := p.parseNameOfClassDeclarationOrExpression() + if kind == ast.KindClassDeclaration && name != nil { + p.updateShadowFlags(name) + } typeParameters := p.parseTypeParameters() if modifiers != nil && core.Some(modifiers.Nodes, isExportModifier) { p.setContextFlags(ast.NodeFlagsAwaitContext, true /*value*/) @@ -1918,10 +1952,12 @@ func (p *Parser) tryParseConstructorDeclaration(pos int, jsdoc jsdocScannerInfo, state := p.mark() if p.token == ast.KindConstructorKeyword || p.token == ast.KindStringLiteral && p.scanner.TokenValue() == "constructor" && p.lookAhead((*Parser).nextTokenIsOpenParen) { p.nextToken() + saveShadowFlags := p.shadowFlags typeParameters := p.parseTypeParameters() parameters := p.parseParameters(ParseFlagsNone) returnType := p.parseReturnType(ast.KindColonToken, false /*isType*/) body := p.parseFunctionBlockOrSemicolon(ParseFlagsNone, diagnostics.X_or_expected) + p.shadowFlags = saveShadowFlags result := p.finishNode(p.factory.NewConstructorDeclaration(modifiers, typeParameters, parameters, returnType, nil /*fullSignature*/, body), pos) p.withJSDoc(result, jsdoc) p.checkJSSyntax(result) @@ -1949,10 +1985,12 @@ func (p *Parser) parsePropertyOrMethodDeclaration(pos int, jsdoc jsdocScannerInf func (p *Parser) parseMethodDeclaration(pos int, jsdoc jsdocScannerInfo, modifiers *ast.ModifierList, asteriskToken *ast.Node, name *ast.Node, questionToken *ast.Node, diagnosticMessage *diagnostics.Message) *ast.Node { signatureFlags := core.IfElse(asteriskToken != nil, ParseFlagsYield, ParseFlagsNone) | core.IfElse(modifierListHasAsync(modifiers), ParseFlagsAwait, ParseFlagsNone) + saveShadowFlags := p.shadowFlags typeParameters := p.parseTypeParameters() parameters := p.parseParameters(signatureFlags) typeNode := p.parseReturnType(ast.KindColonToken, false /*isType*/) body := p.parseFunctionBlockOrSemicolon(signatureFlags, diagnosticMessage) + p.shadowFlags = saveShadowFlags result := p.finishNode(p.factory.NewMethodDeclaration(modifiers, asteriskToken, name, questionToken, typeParameters, parameters, typeNode, nil /*fullSignature*/, body), pos) p.withJSDoc(result, jsdoc) p.checkJSSyntax(result) @@ -2353,6 +2391,7 @@ func (p *Parser) parseImportClause(identifier *ast.Node, pos int, phaseModifier // parse namespace or named imports var namedBindings *ast.Node saveHasAwaitIdentifier := p.statementHasAwaitIdentifier + p.updateShadowFlags(identifier) if identifier == nil || p.parseOptional(ast.KindCommaToken) { if skipJSDocLeadingAsterisks { p.scanner.SetSkipJSDocLeadingAsterisks(true) @@ -2378,6 +2417,7 @@ func (p *Parser) parseNamespaceImport() *ast.Node { p.parseExpected(ast.KindAsteriskToken) p.parseExpected(ast.KindAsKeyword) name := p.parseIdentifier() + p.updateShadowFlags(name) return p.finishNode(p.factory.NewNamespaceImport(name), pos) } @@ -2396,6 +2436,9 @@ func (p *Parser) parseImportSpecifier() *ast.Node { isTypeOnly, propertyName, name := p.parseImportOrExportSpecifier(ast.KindImportSpecifier) var identifierName *ast.Node if name.Kind == ast.KindIdentifier { + if !isTypeOnly { + p.updateShadowFlags(name) + } identifierName = name } else { p.parseErrorAtRange(p.skipRangeTrivia(name.Loc), diagnostics.Identifier_expected) @@ -3204,10 +3247,12 @@ func (p *Parser) parseSignatureMember(kind ast.Kind) *ast.Node { if kind == ast.KindConstructSignature { p.parseExpected(ast.KindNewKeyword) } + saveShadowFlags := p.shadowFlags typeParameters := p.parseTypeParameters() parameters := p.parseParameters(ParseFlagsType) typeNode := p.parseReturnType(ast.KindColonToken /*isType*/, true) p.parseTypeMemberSemicolon() + p.shadowFlags = saveShadowFlags var result *ast.Node if kind == ast.KindCallSignature { result = p.factory.NewCallSignatureDeclaration(typeParameters, parameters, typeNode) @@ -3426,10 +3471,12 @@ func (p *Parser) parseTypeMemberSemicolon() { func (p *Parser) parseAccessorDeclaration(pos int, jsdoc jsdocScannerInfo, modifiers *ast.ModifierList, kind ast.Kind, flags ParseFlags) *ast.Node { name := p.parsePropertyName() + saveShadowFlags := p.shadowFlags typeParameters := p.parseTypeParameters() parameters := p.parseParameters(ParseFlagsNone) returnType := p.parseReturnType(ast.KindColonToken, false /*isType*/) body := p.parseFunctionBlockOrSemicolon(flags, nil /*diagnosticMessage*/) + p.shadowFlags = saveShadowFlags var result *ast.Node // Keep track of `typeParameters` (for both) and `type` (for setters) if they were parsed those indicate grammar errors if kind == ast.KindGetAccessor { @@ -3576,9 +3623,11 @@ func (p *Parser) parsePropertyOrMethodSignature(pos int, jsdoc jsdocScannerInfo, if p.token == ast.KindOpenParenToken || p.token == ast.KindLessThanToken { // Method signatures don't exist in expression contexts. So they have neither // [Yield] nor [Await] + saveShadowFlags := p.shadowFlags typeParameters := p.parseTypeParameters() parameters := p.parseParameters(ParseFlagsType) returnType := p.parseReturnType(ast.KindColonToken /*isType*/, true) + p.shadowFlags = saveShadowFlags result = p.factory.NewMethodSignatureDeclaration(modifiers, name, questionToken, typeParameters, parameters, returnType) } else { typeNode := p.parseTypeAnnotation() @@ -3780,9 +3829,11 @@ func (p *Parser) parseFunctionOrConstructorType() *ast.TypeNode { modifiers := p.parseModifiersForConstructorType() isConstructorType := p.parseOptional(ast.KindNewKeyword) debug.Assert(modifiers == nil || isConstructorType, "Per isStartOfFunctionOrConstructorType, a function type cannot have modifiers.") + saveShadowFlags := p.shadowFlags typeParameters := p.parseTypeParameters() parameters := p.parseParameters(ParseFlagsType) returnType := p.parseReturnType(ast.KindEqualsGreaterThanToken, false /*isType*/) + p.shadowFlags = saveShadowFlags var result *ast.TypeNode if isConstructorType { result = p.factory.NewConstructorTypeNode(modifiers, typeParameters, parameters, returnType) @@ -5692,10 +5743,12 @@ func (p *Parser) parseFunctionExpression() *ast.Expression { default: name = p.parseOptionalBindingIdentifier() } + saveShadowFlags := p.shadowFlags typeParameters := p.parseTypeParameters() parameters := p.parseParameters(signatureFlags) returnType := p.parseReturnType(ast.KindColonToken, false /*isType*/) body := p.parseFunctionBlock(signatureFlags, nil /*diagnosticMessage*/) + p.shadowFlags = saveShadowFlags p.contextFlags = saveContexFlags result := p.factory.NewFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, returnType, nil /*fullSignature*/, body) p.finishNode(result, pos) diff --git a/internal/parser/reparser.go b/internal/parser/reparser.go index 982453ef202..08009fed129 100644 --- a/internal/parser/reparser.go +++ b/internal/parser/reparser.go @@ -36,14 +36,20 @@ func (p *Parser) reparseCommonJS(node *ast.Node, jsdoc []*ast.Node) { var export *ast.Node switch ast.GetAssignmentDeclarationKind(expr) { case ast.JSDeclarationKindModuleExports: - export = p.factory.NewJSExportAssignment(nil, p.factory.DeepCloneReparse(expr.AsBinaryExpression().Right)) + // Reparse a JSExportAssignment if `module` identifier is not shadowed + if p.shadowFlags&ShadowFlagsModule == 0 { + export = p.factory.NewJSExportAssignment(nil, p.factory.DeepCloneReparse(expr.AsBinaryExpression().Right)) + } case ast.JSDeclarationKindExportsProperty: // TODO: Name can sometimes be a string literal, so downstream code needs to handle this - export = p.factory.NewCommonJSExport( - nil, - p.factory.DeepCloneReparse(ast.GetElementOrPropertyAccessName(expr.AsBinaryExpression().Left)), - nil, /*typeNode*/ - p.factory.DeepCloneReparse(expr.AsBinaryExpression().Right)) + // Reparse a CommonJSExport if `exports` identifier is not shadowed + if p.shadowFlags&ShadowFlagsExports == 0 { + export = p.factory.NewCommonJSExport( + nil, + p.factory.DeepCloneReparse(ast.GetElementOrPropertyAccessName(expr.AsBinaryExpression().Left)), + nil, /*typeNode*/ + p.factory.DeepCloneReparse(expr.AsBinaryExpression().Right)) + } } if export == nil { break From a3034a46c0fcc58264f76615ab2cdab4ecdd261b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 5 Apr 2026 10:55:42 -0400 Subject: [PATCH 2/8] Error on CJS `exports.xxx` assignments in ES modules --- internal/checker/checker.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 79171ee859f..b59201067b3 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -2328,6 +2328,8 @@ func (c *Checker) checkSourceElementWorker(node *ast.Node) { c.checkExportDeclaration(node) case ast.KindExportAssignment: c.checkExportAssignment(node) + case ast.KindCommonJSExport: + c.checkCommonJSExport(node) case ast.KindEmptyStatement: c.checkGrammarStatementInAmbientContext(node) case ast.KindDebuggerStatement: @@ -5579,6 +5581,13 @@ func (c *Checker) checkExternalModuleExports(node *ast.Node) { } } +func (c *Checker) checkCommonJSExport(node *ast.Node) { + sourceFile := ast.GetSourceFileOfNode(node) + if sourceFile.ExternalModuleIndicator != nil && sourceFile.ExternalModuleIndicator != sourceFile.AsNode() { + c.error(node, diagnostics.An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements) + } +} + func (c *Checker) hasExportedMembersOfKind(moduleSymbol *ast.Symbol, kind ast.SymbolFlags) bool { for _, symbol := range moduleSymbol.Exports { if symbol.Name != ast.InternalSymbolNameExportEquals && c.getSymbolFlags(symbol)&kind != 0 { From 6415aaf09ec5a2eee51c36bc1d67765362732320 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 5 Apr 2026 10:56:34 -0400 Subject: [PATCH 3/8] Accept new baselines --- .../amdLikeInputDeclarationEmit.errors.txt | 34 ---------------- .../compiler/amdLikeInputDeclarationEmit.js | 1 - .../amdLikeInputDeclarationEmit.symbols | 4 ++ .../amdLikeInputDeclarationEmit.types | 18 ++++----- .../compiler/modulePreserve4.errors.txt | 5 ++- .../compiler/modulePreserve4.errors.txt.diff | 13 +++---- ...eModulesCJSEmit1(module=node18).errors.txt | 5 ++- ...lesCJSEmit1(module=node18).errors.txt.diff | 11 ++---- ...eModulesCJSEmit1(module=node20).errors.txt | 5 ++- ...lesCJSEmit1(module=node20).errors.txt.diff | 11 ++---- ...odulesCJSEmit1(module=nodenext).errors.txt | 5 ++- ...sCJSEmit1(module=nodenext).errors.txt.diff | 11 ++---- ...mdLikeInputDeclarationEmit.errors.txt.diff | 38 ------------------ .../amdLikeInputDeclarationEmit.js.diff | 3 +- .../amdLikeInputDeclarationEmit.symbols.diff | 9 ++++- .../amdLikeInputDeclarationEmit.types.diff | 39 ++++++++++++++++--- 16 files changed, 90 insertions(+), 122 deletions(-) delete mode 100644 testdata/baselines/reference/submodule/compiler/amdLikeInputDeclarationEmit.errors.txt delete mode 100644 testdata/baselines/reference/submoduleAccepted/compiler/amdLikeInputDeclarationEmit.errors.txt.diff diff --git a/testdata/baselines/reference/submodule/compiler/amdLikeInputDeclarationEmit.errors.txt b/testdata/baselines/reference/submodule/compiler/amdLikeInputDeclarationEmit.errors.txt deleted file mode 100644 index 22fd9401a79..00000000000 --- a/testdata/baselines/reference/submodule/compiler/amdLikeInputDeclarationEmit.errors.txt +++ /dev/null @@ -1,34 +0,0 @@ -ExtendedClass.js(17,5): error TS6425: Nested CommonJS export constructs cannot be serialized for declaration emit. - - -==== typing.d.ts (0 errors) ==== - declare function define(name: string, modules: string[], ready: (...modules: unknown[]) => T); -==== deps/BaseClass.d.ts (0 errors) ==== - declare module "deps/BaseClass" { - class BaseClass { - static extends(a: A): new () => A & BaseClass; - } - export = BaseClass; - } -==== ExtendedClass.js (1 errors) ==== - define("lib/ExtendedClass", ["deps/BaseClass"], - /** - * {typeof import("deps/BaseClass")} - * @param {typeof import("deps/BaseClass")} BaseClass - * @returns - */ - (BaseClass) => { - - const ExtendedClass = BaseClass.extends({ - f: function() { - return "something"; - } - }); - - // Exports the module in a way tsc recognize class export - const module = {}; - module.exports = ExtendedClass - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS6425: Nested CommonJS export constructs cannot be serialized for declaration emit. - return module.exports; - }); \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/compiler/amdLikeInputDeclarationEmit.js b/testdata/baselines/reference/submodule/compiler/amdLikeInputDeclarationEmit.js index 7777bb555a1..5c8ffab0935 100644 --- a/testdata/baselines/reference/submodule/compiler/amdLikeInputDeclarationEmit.js +++ b/testdata/baselines/reference/submodule/compiler/amdLikeInputDeclarationEmit.js @@ -33,4 +33,3 @@ define("lib/ExtendedClass", ["deps/BaseClass"], //// [ExtendedClass.d.ts] -export {}; diff --git a/testdata/baselines/reference/submodule/compiler/amdLikeInputDeclarationEmit.symbols b/testdata/baselines/reference/submodule/compiler/amdLikeInputDeclarationEmit.symbols index 0dff24a11ac..e846238643c 100644 --- a/testdata/baselines/reference/submodule/compiler/amdLikeInputDeclarationEmit.symbols +++ b/testdata/baselines/reference/submodule/compiler/amdLikeInputDeclarationEmit.symbols @@ -58,10 +58,14 @@ define("lib/ExtendedClass", ["deps/BaseClass"], >module : Symbol(module, Decl(ExtendedClass.js, 15, 9)) module.exports = ExtendedClass +>module.exports : Symbol(exports, Decl(ExtendedClass.js, 15, 22)) >module : Symbol(module, Decl(ExtendedClass.js, 15, 9)) +>exports : Symbol(exports, Decl(ExtendedClass.js, 15, 22)) >ExtendedClass : Symbol(ExtendedClass, Decl(ExtendedClass.js, 8, 9)) return module.exports; +>module.exports : Symbol(exports, Decl(ExtendedClass.js, 15, 22)) >module : Symbol(module, Decl(ExtendedClass.js, 15, 9)) +>exports : Symbol(exports, Decl(ExtendedClass.js, 15, 22)) }); diff --git a/testdata/baselines/reference/submodule/compiler/amdLikeInputDeclarationEmit.types b/testdata/baselines/reference/submodule/compiler/amdLikeInputDeclarationEmit.types index 09b41665051..341367a9c1b 100644 --- a/testdata/baselines/reference/submodule/compiler/amdLikeInputDeclarationEmit.types +++ b/testdata/baselines/reference/submodule/compiler/amdLikeInputDeclarationEmit.types @@ -36,7 +36,7 @@ define("lib/ExtendedClass", ["deps/BaseClass"], * @returns */ (BaseClass) => { ->(BaseClass) => { const ExtendedClass = BaseClass.extends({ f: function() { return "something"; } }); // Exports the module in a way tsc recognize class export const module = {}; module.exports = ExtendedClass return module.exports;} : (BaseClass: typeof import("deps/BaseClass")) => any +>(BaseClass) => { const ExtendedClass = BaseClass.extends({ f: function() { return "something"; } }); // Exports the module in a way tsc recognize class export const module = {}; module.exports = ExtendedClass return module.exports;} : (BaseClass: typeof import("deps/BaseClass")) => new () => { f: () => "something"; } & import("deps/BaseClass") >BaseClass : typeof import("deps/BaseClass") const ExtendedClass = BaseClass.extends({ @@ -58,19 +58,19 @@ define("lib/ExtendedClass", ["deps/BaseClass"], // Exports the module in a way tsc recognize class export const module = {}; ->module : {} ->{} : {} +>module : { exports: new () => { f: () => "something"; } & import("deps/BaseClass"); } +>{} : { exports: new () => { f: () => "something"; } & import("deps/BaseClass"); } module.exports = ExtendedClass >module.exports = ExtendedClass : new () => { f: () => "something"; } & import("deps/BaseClass") ->module.exports : any ->module : {} ->exports : any +>module.exports : new () => { f: () => "something"; } & import("deps/BaseClass") +>module : { exports: new () => { f: () => "something"; } & import("deps/BaseClass"); } +>exports : new () => { f: () => "something"; } & import("deps/BaseClass") >ExtendedClass : new () => { f: () => "something"; } & import("deps/BaseClass") return module.exports; ->module.exports : any ->module : {} ->exports : any +>module.exports : new () => { f: () => "something"; } & import("deps/BaseClass") +>module : { exports: new () => { f: () => "something"; } & import("deps/BaseClass"); } +>exports : new () => { f: () => "something"; } & import("deps/BaseClass") }); diff --git a/testdata/baselines/reference/submodule/compiler/modulePreserve4.errors.txt b/testdata/baselines/reference/submodule/compiler/modulePreserve4.errors.txt index 36ac9d5916d..8a4b8976cb3 100644 --- a/testdata/baselines/reference/submodule/compiler/modulePreserve4.errors.txt +++ b/testdata/baselines/reference/submodule/compiler/modulePreserve4.errors.txt @@ -1,3 +1,4 @@ +/a.js(2,1): error TS2309: An export assignment cannot be used in a module with other exported elements. /f.cts(1,1): error TS1286: ECMAScript imports and exports cannot be written in a CommonJS file under 'verbatimModuleSyntax'. /main1.ts(3,12): error TS2591: Cannot find name 'require'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig. /main1.ts(19,4): error TS2339: Property 'default' does not exist on type '() => void'. @@ -16,9 +17,11 @@ /main3.cjs(17,8): error TS1293: ECMAScript module syntax is not allowed in a CommonJS module when 'module' is set to 'preserve'. -==== /a.js (0 errors) ==== +==== /a.js (1 errors) ==== export const x = 0; module.exports.y = 0; // Error + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2309: An export assignment cannot be used in a module with other exported elements. ==== /b.ts (0 errors) ==== export default 0; diff --git a/testdata/baselines/reference/submodule/compiler/modulePreserve4.errors.txt.diff b/testdata/baselines/reference/submodule/compiler/modulePreserve4.errors.txt.diff index e00ac3e8454..0a4e693c259 100644 --- a/testdata/baselines/reference/submodule/compiler/modulePreserve4.errors.txt.diff +++ b/testdata/baselines/reference/submodule/compiler/modulePreserve4.errors.txt.diff @@ -2,6 +2,7 @@ +++ new.modulePreserve4.errors.txt @@= skipped -0, +0 lines =@@ -/a.js(2,1): error TS2591: Cannot find name 'module'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig. ++/a.js(2,1): error TS2309: An export assignment cannot be used in a module with other exported elements. /f.cts(1,1): error TS1286: ECMAScript imports and exports cannot be written in a CommonJS file under 'verbatimModuleSyntax'. -/main1.ts(1,13): error TS2305: Module '"./a"' has no exported member 'y'. /main1.ts(3,12): error TS2591: Cannot find name 'require'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig. @@ -17,20 +18,18 @@ /main3.cjs(2,1): error TS8002: 'import ... =' can only be used in TypeScript files. /main3.cjs(5,8): error TS1293: ECMAScript module syntax is not allowed in a CommonJS module when 'module' is set to 'preserve'. /main3.cjs(8,8): error TS1293: ECMAScript module syntax is not allowed in a CommonJS module when 'module' is set to 'preserve'. -@@= skipped -18, +15 lines =@@ - /main3.cjs(17,8): error TS1293: ECMAScript module syntax is not allowed in a CommonJS module when 'module' is set to 'preserve'. - - --==== /a.js (1 errors) ==== -+==== /a.js (0 errors) ==== +@@= skipped -21, +19 lines =@@ + ==== /a.js (1 errors) ==== export const x = 0; module.exports.y = 0; // Error - ~~~~~~ -!!! error TS2591: Cannot find name 'module'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig. ++ ~~~~~~~~~~~~~~~~~~~~ ++!!! error TS2309: An export assignment cannot be used in a module with other exported elements. ==== /b.ts (0 errors) ==== export default 0; -@@= skipped -28, +26 lines =@@ +@@= skipped -25, +25 lines =@@ ==== /g.js (0 errors) ==== exports.default = 0; diff --git a/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=node18).errors.txt b/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=node18).errors.txt index 65574d181dd..2343f91a029 100644 --- a/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=node18).errors.txt +++ b/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=node18).errors.txt @@ -1,4 +1,5 @@ /3.cjs(1,8): error TS2882: Cannot find module or type declarations for side-effect import of 'foo'. +/3.cjs(2,1): error TS2309: An export assignment cannot be used in a module with other exported elements. /5.cjs(2,8): error TS1192: Module '"/3"' has no default export. @@ -8,11 +9,13 @@ ==== /2.cjs (0 errors) ==== exports.foo = 0; -==== /3.cjs (1 errors) ==== +==== /3.cjs (2 errors) ==== import "foo"; ~~~~~ !!! error TS2882: Cannot find module or type declarations for side-effect import of 'foo'. exports.foo = {}; + ~~~~~~~~~~~~~~~~ +!!! error TS2309: An export assignment cannot be used in a module with other exported elements. ==== /4.cjs (0 errors) ==== ; diff --git a/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=node18).errors.txt.diff b/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=node18).errors.txt.diff index 95cdf26767f..5bbb3cd7540 100644 --- a/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=node18).errors.txt.diff +++ b/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=node18).errors.txt.diff @@ -3,21 +3,18 @@ @@= skipped -0, +0 lines =@@ /3.cjs(1,8): error TS2882: Cannot find module or type declarations for side-effect import of 'foo'. -/3.cjs(2,1): error TS2304: Cannot find name 'exports'. ++/3.cjs(2,1): error TS2309: An export assignment cannot be used in a module with other exported elements. /5.cjs(2,8): error TS1192: Module '"/3"' has no default export. -@@= skipped -8, +7 lines =@@ - ==== /2.cjs (0 errors) ==== - exports.foo = 0; - --==== /3.cjs (2 errors) ==== -+==== /3.cjs (1 errors) ==== - import "foo"; +@@= skipped -13, +13 lines =@@ ~~~~~ !!! error TS2882: Cannot find module or type declarations for side-effect import of 'foo'. exports.foo = {}; - ~~~~~~~ -!!! error TS2304: Cannot find name 'exports'. ++ ~~~~~~~~~~~~~~~~ ++!!! error TS2309: An export assignment cannot be used in a module with other exported elements. ==== /4.cjs (0 errors) ==== ; \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=node20).errors.txt b/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=node20).errors.txt index 65574d181dd..2343f91a029 100644 --- a/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=node20).errors.txt +++ b/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=node20).errors.txt @@ -1,4 +1,5 @@ /3.cjs(1,8): error TS2882: Cannot find module or type declarations for side-effect import of 'foo'. +/3.cjs(2,1): error TS2309: An export assignment cannot be used in a module with other exported elements. /5.cjs(2,8): error TS1192: Module '"/3"' has no default export. @@ -8,11 +9,13 @@ ==== /2.cjs (0 errors) ==== exports.foo = 0; -==== /3.cjs (1 errors) ==== +==== /3.cjs (2 errors) ==== import "foo"; ~~~~~ !!! error TS2882: Cannot find module or type declarations for side-effect import of 'foo'. exports.foo = {}; + ~~~~~~~~~~~~~~~~ +!!! error TS2309: An export assignment cannot be used in a module with other exported elements. ==== /4.cjs (0 errors) ==== ; diff --git a/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=node20).errors.txt.diff b/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=node20).errors.txt.diff index ed15731072f..13abe9fb29d 100644 --- a/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=node20).errors.txt.diff +++ b/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=node20).errors.txt.diff @@ -3,21 +3,18 @@ @@= skipped -0, +0 lines =@@ /3.cjs(1,8): error TS2882: Cannot find module or type declarations for side-effect import of 'foo'. -/3.cjs(2,1): error TS2304: Cannot find name 'exports'. ++/3.cjs(2,1): error TS2309: An export assignment cannot be used in a module with other exported elements. /5.cjs(2,8): error TS1192: Module '"/3"' has no default export. -@@= skipped -8, +7 lines =@@ - ==== /2.cjs (0 errors) ==== - exports.foo = 0; - --==== /3.cjs (2 errors) ==== -+==== /3.cjs (1 errors) ==== - import "foo"; +@@= skipped -13, +13 lines =@@ ~~~~~ !!! error TS2882: Cannot find module or type declarations for side-effect import of 'foo'. exports.foo = {}; - ~~~~~~~ -!!! error TS2304: Cannot find name 'exports'. ++ ~~~~~~~~~~~~~~~~ ++!!! error TS2309: An export assignment cannot be used in a module with other exported elements. ==== /4.cjs (0 errors) ==== ; \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=nodenext).errors.txt b/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=nodenext).errors.txt index 65574d181dd..2343f91a029 100644 --- a/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=nodenext).errors.txt +++ b/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=nodenext).errors.txt @@ -1,4 +1,5 @@ /3.cjs(1,8): error TS2882: Cannot find module or type declarations for side-effect import of 'foo'. +/3.cjs(2,1): error TS2309: An export assignment cannot be used in a module with other exported elements. /5.cjs(2,8): error TS1192: Module '"/3"' has no default export. @@ -8,11 +9,13 @@ ==== /2.cjs (0 errors) ==== exports.foo = 0; -==== /3.cjs (1 errors) ==== +==== /3.cjs (2 errors) ==== import "foo"; ~~~~~ !!! error TS2882: Cannot find module or type declarations for side-effect import of 'foo'. exports.foo = {}; + ~~~~~~~~~~~~~~~~ +!!! error TS2309: An export assignment cannot be used in a module with other exported elements. ==== /4.cjs (0 errors) ==== ; diff --git a/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=nodenext).errors.txt.diff b/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=nodenext).errors.txt.diff index 6dc03e4128e..55bcc98b192 100644 --- a/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=nodenext).errors.txt.diff +++ b/testdata/baselines/reference/submodule/conformance/nodeModulesCJSEmit1(module=nodenext).errors.txt.diff @@ -3,21 +3,18 @@ @@= skipped -0, +0 lines =@@ /3.cjs(1,8): error TS2882: Cannot find module or type declarations for side-effect import of 'foo'. -/3.cjs(2,1): error TS2304: Cannot find name 'exports'. ++/3.cjs(2,1): error TS2309: An export assignment cannot be used in a module with other exported elements. /5.cjs(2,8): error TS1192: Module '"/3"' has no default export. -@@= skipped -8, +7 lines =@@ - ==== /2.cjs (0 errors) ==== - exports.foo = 0; - --==== /3.cjs (2 errors) ==== -+==== /3.cjs (1 errors) ==== - import "foo"; +@@= skipped -13, +13 lines =@@ ~~~~~ !!! error TS2882: Cannot find module or type declarations for side-effect import of 'foo'. exports.foo = {}; - ~~~~~~~ -!!! error TS2304: Cannot find name 'exports'. ++ ~~~~~~~~~~~~~~~~ ++!!! error TS2309: An export assignment cannot be used in a module with other exported elements. ==== /4.cjs (0 errors) ==== ; \ No newline at end of file diff --git a/testdata/baselines/reference/submoduleAccepted/compiler/amdLikeInputDeclarationEmit.errors.txt.diff b/testdata/baselines/reference/submoduleAccepted/compiler/amdLikeInputDeclarationEmit.errors.txt.diff deleted file mode 100644 index b4fe80c2893..00000000000 --- a/testdata/baselines/reference/submoduleAccepted/compiler/amdLikeInputDeclarationEmit.errors.txt.diff +++ /dev/null @@ -1,38 +0,0 @@ ---- old.amdLikeInputDeclarationEmit.errors.txt -+++ new.amdLikeInputDeclarationEmit.errors.txt -@@= skipped -0, +0 lines =@@ -- -+ExtendedClass.js(17,5): error TS6425: Nested CommonJS export constructs cannot be serialized for declaration emit. -+ -+ -+==== typing.d.ts (0 errors) ==== -+ declare function define(name: string, modules: string[], ready: (...modules: unknown[]) => T); -+==== deps/BaseClass.d.ts (0 errors) ==== -+ declare module "deps/BaseClass" { -+ class BaseClass { -+ static extends(a: A): new () => A & BaseClass; -+ } -+ export = BaseClass; -+ } -+==== ExtendedClass.js (1 errors) ==== -+ define("lib/ExtendedClass", ["deps/BaseClass"], -+ /** -+ * {typeof import("deps/BaseClass")} -+ * @param {typeof import("deps/BaseClass")} BaseClass -+ * @returns -+ */ -+ (BaseClass) => { -+ -+ const ExtendedClass = BaseClass.extends({ -+ f: function() { -+ return "something"; -+ } -+ }); -+ -+ // Exports the module in a way tsc recognize class export -+ const module = {}; -+ module.exports = ExtendedClass -+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+!!! error TS6425: Nested CommonJS export constructs cannot be serialized for declaration emit. -+ return module.exports; -+ }); \ No newline at end of file diff --git a/testdata/baselines/reference/submoduleAccepted/compiler/amdLikeInputDeclarationEmit.js.diff b/testdata/baselines/reference/submoduleAccepted/compiler/amdLikeInputDeclarationEmit.js.diff index 6965dca877e..889fa297e44 100644 --- a/testdata/baselines/reference/submoduleAccepted/compiler/amdLikeInputDeclarationEmit.js.diff +++ b/testdata/baselines/reference/submoduleAccepted/compiler/amdLikeInputDeclarationEmit.js.diff @@ -7,5 +7,4 @@ -export = ExtendedClass; -declare const ExtendedClass: new () => { - f: () => "something"; --} & import("deps/BaseClass"); -+export {}; \ No newline at end of file +-} & import("deps/BaseClass"); \ No newline at end of file diff --git a/testdata/baselines/reference/submoduleAccepted/compiler/amdLikeInputDeclarationEmit.symbols.diff b/testdata/baselines/reference/submoduleAccepted/compiler/amdLikeInputDeclarationEmit.symbols.diff index 301886ab243..09f371c3945 100644 --- a/testdata/baselines/reference/submoduleAccepted/compiler/amdLikeInputDeclarationEmit.symbols.diff +++ b/testdata/baselines/reference/submoduleAccepted/compiler/amdLikeInputDeclarationEmit.symbols.diff @@ -6,7 +6,14 @@ module.exports = ExtendedClass ->module : Symbol(export=, Decl(ExtendedClass.js, 15, 22)) ->exports : Symbol(export=, Decl(ExtendedClass.js, 15, 22)) ++>module.exports : Symbol(exports, Decl(ExtendedClass.js, 15, 22)) +>module : Symbol(module, Decl(ExtendedClass.js, 15, 9)) ++>exports : Symbol(exports, Decl(ExtendedClass.js, 15, 22)) >ExtendedClass : Symbol(ExtendedClass, Decl(ExtendedClass.js, 8, 9)) - return module.exports; \ No newline at end of file + return module.exports; ++>module.exports : Symbol(exports, Decl(ExtendedClass.js, 15, 22)) + >module : Symbol(module, Decl(ExtendedClass.js, 15, 9)) ++>exports : Symbol(exports, Decl(ExtendedClass.js, 15, 22)) + + }); \ No newline at end of file diff --git a/testdata/baselines/reference/submoduleAccepted/compiler/amdLikeInputDeclarationEmit.types.diff b/testdata/baselines/reference/submoduleAccepted/compiler/amdLikeInputDeclarationEmit.types.diff index 6b45583edcd..6c19a2ea520 100644 --- a/testdata/baselines/reference/submoduleAccepted/compiler/amdLikeInputDeclarationEmit.types.diff +++ b/testdata/baselines/reference/submoduleAccepted/compiler/amdLikeInputDeclarationEmit.types.diff @@ -1,11 +1,40 @@ --- old.amdLikeInputDeclarationEmit.types +++ new.amdLikeInputDeclarationEmit.types -@@= skipped -61, +61 lines =@@ - >{} : {} +@@= skipped -35, +35 lines =@@ + * @returns + */ + (BaseClass) => { +->(BaseClass) => { const ExtendedClass = BaseClass.extends({ f: function() { return "something"; } }); // Exports the module in a way tsc recognize class export const module = {}; module.exports = ExtendedClass return module.exports;} : (BaseClass: typeof import("deps/BaseClass")) => any ++>(BaseClass) => { const ExtendedClass = BaseClass.extends({ f: function() { return "something"; } }); // Exports the module in a way tsc recognize class export const module = {}; module.exports = ExtendedClass return module.exports;} : (BaseClass: typeof import("deps/BaseClass")) => new () => { f: () => "something"; } & import("deps/BaseClass") + >BaseClass : typeof import("deps/BaseClass") + + const ExtendedClass = BaseClass.extends({ +@@= skipped -22, +22 lines =@@ + + // Exports the module in a way tsc recognize class export + const module = {}; +->module : {} +->{} : {} ++>module : { exports: new () => { f: () => "something"; } & import("deps/BaseClass"); } ++>{} : { exports: new () => { f: () => "something"; } & import("deps/BaseClass"); } module.exports = ExtendedClass ->module.exports = ExtendedClass : any +->module.exports : any +->module : {} +->exports : any +>module.exports = ExtendedClass : new () => { f: () => "something"; } & import("deps/BaseClass") - >module.exports : any - >module : {} - >exports : any \ No newline at end of file ++>module.exports : new () => { f: () => "something"; } & import("deps/BaseClass") ++>module : { exports: new () => { f: () => "something"; } & import("deps/BaseClass"); } ++>exports : new () => { f: () => "something"; } & import("deps/BaseClass") + >ExtendedClass : new () => { f: () => "something"; } & import("deps/BaseClass") + + return module.exports; +->module.exports : any +->module : {} +->exports : any ++>module.exports : new () => { f: () => "something"; } & import("deps/BaseClass") ++>module : { exports: new () => { f: () => "something"; } & import("deps/BaseClass"); } ++>exports : new () => { f: () => "something"; } & import("deps/BaseClass") + + }); \ No newline at end of file From ba1e5fdd243b74f8e799559b991e570bdf764be1 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 5 Apr 2026 10:56:48 -0400 Subject: [PATCH 4/8] Add tests --- ...ModuleWithShadowedModuleIdentifier.symbols | 20 ++ ...esModuleWithShadowedModuleIdentifier.types | 26 ++ .../compiler/shadowedExportsIdentifier.js | 165 ++++++++++++ .../shadowedExportsIdentifier.symbols | 190 +++++++++++++ .../compiler/shadowedExportsIdentifier.types | 249 ++++++++++++++++++ .../compiler/shadowedModuleIdentifier.js | 165 ++++++++++++ .../compiler/shadowedModuleIdentifier.symbols | 190 +++++++++++++ .../compiler/shadowedModuleIdentifier.types | 249 ++++++++++++++++++ .../esModuleWithShadowedModuleIdentifier.ts | 16 ++ .../compiler/shadowedExportsIdentifier.ts | 91 +++++++ .../compiler/shadowedModuleIdentifier.ts | 91 +++++++ 11 files changed, 1452 insertions(+) create mode 100644 testdata/baselines/reference/compiler/esModuleWithShadowedModuleIdentifier.symbols create mode 100644 testdata/baselines/reference/compiler/esModuleWithShadowedModuleIdentifier.types create mode 100644 testdata/baselines/reference/compiler/shadowedExportsIdentifier.js create mode 100644 testdata/baselines/reference/compiler/shadowedExportsIdentifier.symbols create mode 100644 testdata/baselines/reference/compiler/shadowedExportsIdentifier.types create mode 100644 testdata/baselines/reference/compiler/shadowedModuleIdentifier.js create mode 100644 testdata/baselines/reference/compiler/shadowedModuleIdentifier.symbols create mode 100644 testdata/baselines/reference/compiler/shadowedModuleIdentifier.types create mode 100644 testdata/tests/cases/compiler/esModuleWithShadowedModuleIdentifier.ts create mode 100644 testdata/tests/cases/compiler/shadowedExportsIdentifier.ts create mode 100644 testdata/tests/cases/compiler/shadowedModuleIdentifier.ts diff --git a/testdata/baselines/reference/compiler/esModuleWithShadowedModuleIdentifier.symbols b/testdata/baselines/reference/compiler/esModuleWithShadowedModuleIdentifier.symbols new file mode 100644 index 00000000000..df47ed986db --- /dev/null +++ b/testdata/baselines/reference/compiler/esModuleWithShadowedModuleIdentifier.symbols @@ -0,0 +1,20 @@ +//// [tests/cases/compiler/esModuleWithShadowedModuleIdentifier.ts] //// + +=== dep.js === +function something(module) { +>something : Symbol(something, Decl(dep.js, 0, 0)) +>module : Symbol(module, Decl(dep.js, 0, 19)) + + module.exports = 8; +>module : Symbol(module, Decl(dep.js, 0, 19)) +} + +export default 7; + +=== main.ts === +import DefaultExport from "./dep.js"; +>DefaultExport : Symbol(DefaultExport, Decl(main.ts, 0, 6)) + +export default 3 + DefaultExport; +>DefaultExport : Symbol(DefaultExport, Decl(main.ts, 0, 6)) + diff --git a/testdata/baselines/reference/compiler/esModuleWithShadowedModuleIdentifier.types b/testdata/baselines/reference/compiler/esModuleWithShadowedModuleIdentifier.types new file mode 100644 index 00000000000..f75742423bc --- /dev/null +++ b/testdata/baselines/reference/compiler/esModuleWithShadowedModuleIdentifier.types @@ -0,0 +1,26 @@ +//// [tests/cases/compiler/esModuleWithShadowedModuleIdentifier.ts] //// + +=== dep.js === +function something(module) { +>something : (module: any) => void +>module : any + + module.exports = 8; +>module.exports = 8 : 8 +>module.exports : any +>module : any +>exports : any +>8 : 8 +} + +export default 7; + +=== main.ts === +import DefaultExport from "./dep.js"; +>DefaultExport : 7 + +export default 3 + DefaultExport; +>3 + DefaultExport : number +>3 : 3 +>DefaultExport : 7 + diff --git a/testdata/baselines/reference/compiler/shadowedExportsIdentifier.js b/testdata/baselines/reference/compiler/shadowedExportsIdentifier.js new file mode 100644 index 00000000000..e4ba6cc5b9f --- /dev/null +++ b/testdata/baselines/reference/compiler/shadowedExportsIdentifier.js @@ -0,0 +1,165 @@ +//// [tests/cases/compiler/shadowedExportsIdentifier.ts] //// + +//// [main.js] +// Each `exports.a` assignment in this file is supposed to reference an `exports` local. +// If it doesn't, the `exports.a` assignment will conflict with the ESM export below. + +export const foo = 1 + +function f1(/** @type {any} */ exports) { + exports.a = 1 +} + +function f2(/** @type {any} */ { exports }) { + exports.a = 1 +} + +function f3(/** @type {any} */ { x: exports }) { + exports.a = 1 +} + +function f4(/** @type {any} */ [exports]) { + exports.a = 1 +} + +function f10() { + let exports = {} + exports.a = 1 +} + +function f11() { + let { exports } = { exports: { a: 0 } } + exports.a = 1 +} + +function f12() { + let exports = {} + while (true) { + exports.a = 1 + } +} + +function f13() { + let exports = { a: 0 } + function g() { + exports.a = 1 + } +} + +function f14() { + let exports = { a: 0 } + const g = () => { + exports.a = 1 + } +} + +function f15() { + const exports = {} + exports.a = 1 +} + +function f16() { + var exports = {} + exports.a = 1 +} + +function f17() { + function exports() {} + exports.a = 1 +} + +function f18() { + class exports {} + exports.a = 1 +} + +function f19() { + for (const exports of [{ a: 0 }]) { + exports.a = 1 + } +} + +function f20() { + try { + } + catch (/** @type {any} */ exports) { + exports.a = 1 + } +} + + +//// [main.js] +// Each `exports.a` assignment in this file is supposed to reference an `exports` local. +// If it doesn't, the `exports.a` assignment will conflict with the ESM export below. +export const foo = 1; +function f1(/** @type {any} */ exports) { + exports.a = 1; +} +function f2(/** @type {any} */ { exports }) { + exports.a = 1; +} +function f3(/** @type {any} */ { x: exports }) { + exports.a = 1; +} +function f4(/** @type {any} */ [exports]) { + exports.a = 1; +} +function f10() { + let exports = {}; + exports.a = 1; +} +function f11() { + let { exports } = { exports: { a: 0 } }; + exports.a = 1; +} +function f12() { + let exports = {}; + while (true) { + exports.a = 1; + } +} +function f13() { + let exports = { a: 0 }; + function g() { + exports.a = 1; + } +} +function f14() { + let exports = { a: 0 }; + const g = () => { + exports.a = 1; + }; +} +function f15() { + const exports = {}; + exports.a = 1; +} +function f16() { + var exports = {}; + exports.a = 1; +} +function f17() { + function exports() { } + exports.a = 1; +} +function f18() { + class exports { + } + exports.a = 1; +} +function f19() { + for (const exports of [{ a: 0 }]) { + exports.a = 1; + } +} +function f20() { + try { + } + catch ( /** @type {any} */exports) { + exports.a = 1; + } +} + + +//// [main.d.ts] +export declare const foo = 1; diff --git a/testdata/baselines/reference/compiler/shadowedExportsIdentifier.symbols b/testdata/baselines/reference/compiler/shadowedExportsIdentifier.symbols new file mode 100644 index 00000000000..c3e40f3bacd --- /dev/null +++ b/testdata/baselines/reference/compiler/shadowedExportsIdentifier.symbols @@ -0,0 +1,190 @@ +//// [tests/cases/compiler/shadowedExportsIdentifier.ts] //// + +=== main.js === +// Each `exports.a` assignment in this file is supposed to reference an `exports` local. +// If it doesn't, the `exports.a` assignment will conflict with the ESM export below. + +export const foo = 1 +>foo : Symbol(foo, Decl(main.js, 3, 12)) + +function f1(/** @type {any} */ exports) { +>f1 : Symbol(f1, Decl(main.js, 3, 20)) +>exports : Symbol(exports, Decl(main.js, 5, 12)) + + exports.a = 1 +>exports : Symbol(exports, Decl(main.js, 5, 12)) +} + +function f2(/** @type {any} */ { exports }) { +>f2 : Symbol(f2, Decl(main.js, 7, 1)) +>exports : Symbol(exports, Decl(main.js, 9, 32)) + + exports.a = 1 +>exports : Symbol(exports, Decl(main.js, 9, 32)) +} + +function f3(/** @type {any} */ { x: exports }) { +>f3 : Symbol(f3, Decl(main.js, 11, 1)) +>exports : Symbol(exports, Decl(main.js, 13, 32)) + + exports.a = 1 +>exports : Symbol(exports, Decl(main.js, 13, 32)) +} + +function f4(/** @type {any} */ [exports]) { +>f4 : Symbol(f4, Decl(main.js, 15, 1)) +>exports : Symbol(exports, Decl(main.js, 17, 32)) + + exports.a = 1 +>exports : Symbol(exports, Decl(main.js, 17, 32)) +} + +function f10() { +>f10 : Symbol(f10, Decl(main.js, 19, 1)) + + let exports = {} +>exports : Symbol(exports, Decl(main.js, 22, 7)) + + exports.a = 1 +>exports.a : Symbol(a, Decl(main.js, 22, 20)) +>exports : Symbol(exports, Decl(main.js, 22, 7)) +>a : Symbol(a, Decl(main.js, 22, 20)) +} + +function f11() { +>f11 : Symbol(f11, Decl(main.js, 24, 1)) + + let { exports } = { exports: { a: 0 } } +>exports : Symbol(exports, Decl(main.js, 27, 9)) +>exports : Symbol(exports, Decl(main.js, 27, 23)) +>a : Symbol(a, Decl(main.js, 27, 34)) + + exports.a = 1 +>exports.a : Symbol(a, Decl(main.js, 27, 34)) +>exports : Symbol(exports, Decl(main.js, 27, 9)) +>a : Symbol(a, Decl(main.js, 27, 34)) +} + +function f12() { +>f12 : Symbol(f12, Decl(main.js, 29, 1)) + + let exports = {} +>exports : Symbol(exports, Decl(main.js, 32, 7)) + + while (true) { + exports.a = 1 +>exports.a : Symbol(a, Decl(main.js, 33, 18)) +>exports : Symbol(exports, Decl(main.js, 32, 7)) +>a : Symbol(a, Decl(main.js, 33, 18)) + } +} + +function f13() { +>f13 : Symbol(f13, Decl(main.js, 36, 1)) + + let exports = { a: 0 } +>exports : Symbol(exports, Decl(main.js, 39, 7)) +>a : Symbol(a, Decl(main.js, 39, 19)) + + function g() { +>g : Symbol(g, Decl(main.js, 39, 26)) + + exports.a = 1 +>exports.a : Symbol(a, Decl(main.js, 39, 19)) +>exports : Symbol(exports, Decl(main.js, 39, 7)) +>a : Symbol(a, Decl(main.js, 39, 19)) + } +} + +function f14() { +>f14 : Symbol(f14, Decl(main.js, 43, 1)) + + let exports = { a: 0 } +>exports : Symbol(exports, Decl(main.js, 46, 7)) +>a : Symbol(a, Decl(main.js, 46, 19)) + + const g = () => { +>g : Symbol(g, Decl(main.js, 47, 9)) + + exports.a = 1 +>exports.a : Symbol(a, Decl(main.js, 46, 19)) +>exports : Symbol(exports, Decl(main.js, 46, 7)) +>a : Symbol(a, Decl(main.js, 46, 19)) + } +} + +function f15() { +>f15 : Symbol(f15, Decl(main.js, 50, 1)) + + const exports = {} +>exports : Symbol(exports, Decl(main.js, 53, 9)) + + exports.a = 1 +>exports.a : Symbol(a, Decl(main.js, 53, 22)) +>exports : Symbol(exports, Decl(main.js, 53, 9)) +>a : Symbol(a, Decl(main.js, 53, 22)) +} + +function f16() { +>f16 : Symbol(f16, Decl(main.js, 55, 1)) + + var exports = {} +>exports : Symbol(exports, Decl(main.js, 58, 7)) + + exports.a = 1 +>exports.a : Symbol(a, Decl(main.js, 58, 20)) +>exports : Symbol(exports, Decl(main.js, 58, 7)) +>a : Symbol(a, Decl(main.js, 58, 20)) +} + +function f17() { +>f17 : Symbol(f17, Decl(main.js, 60, 1)) + + function exports() {} +>exports : Symbol(exports, Decl(main.js, 62, 16)) + + exports.a = 1 +>exports.a : Symbol(exports.a, Decl(main.js, 63, 25)) +>exports : Symbol(exports, Decl(main.js, 62, 16)) +>a : Symbol(exports.a, Decl(main.js, 63, 25)) +} + +function f18() { +>f18 : Symbol(f18, Decl(main.js, 65, 1)) + + class exports {} +>exports : Symbol(exports, Decl(main.js, 67, 16)) + + exports.a = 1 +>exports.a : Symbol(exports.a, Decl(main.js, 68, 20)) +>exports : Symbol(exports, Decl(main.js, 67, 16)) +>a : Symbol(exports.a, Decl(main.js, 68, 20)) +} + +function f19() { +>f19 : Symbol(f19, Decl(main.js, 70, 1)) + + for (const exports of [{ a: 0 }]) { +>exports : Symbol(exports, Decl(main.js, 73, 14)) +>a : Symbol(a, Decl(main.js, 73, 28)) + + exports.a = 1 +>exports.a : Symbol(a, Decl(main.js, 73, 28)) +>exports : Symbol(exports, Decl(main.js, 73, 14)) +>a : Symbol(a, Decl(main.js, 73, 28)) + } +} + +function f20() { +>f20 : Symbol(f20, Decl(main.js, 76, 1)) + + try { + } + catch (/** @type {any} */ exports) { +>exports : Symbol(exports, Decl(main.js, 81, 11)) + + exports.a = 1 +>exports : Symbol(exports, Decl(main.js, 81, 11)) + } +} + diff --git a/testdata/baselines/reference/compiler/shadowedExportsIdentifier.types b/testdata/baselines/reference/compiler/shadowedExportsIdentifier.types new file mode 100644 index 00000000000..69357e6324f --- /dev/null +++ b/testdata/baselines/reference/compiler/shadowedExportsIdentifier.types @@ -0,0 +1,249 @@ +//// [tests/cases/compiler/shadowedExportsIdentifier.ts] //// + +=== main.js === +// Each `exports.a` assignment in this file is supposed to reference an `exports` local. +// If it doesn't, the `exports.a` assignment will conflict with the ESM export below. + +export const foo = 1 +>foo : 1 +>1 : 1 + +function f1(/** @type {any} */ exports) { +>f1 : (exports: any) => void +>exports : any + + exports.a = 1 +>exports.a = 1 : 1 +>exports.a : any +>exports : any +>a : any +>1 : 1 +} + +function f2(/** @type {any} */ { exports }) { +>f2 : ({ exports }: any) => void +>exports : any + + exports.a = 1 +>exports.a = 1 : 1 +>exports.a : any +>exports : any +>a : any +>1 : 1 +} + +function f3(/** @type {any} */ { x: exports }) { +>f3 : ({ x: exports }: any) => void +>x : any +>exports : any + + exports.a = 1 +>exports.a = 1 : 1 +>exports.a : any +>exports : any +>a : any +>1 : 1 +} + +function f4(/** @type {any} */ [exports]) { +>f4 : ([exports]: any) => void +>exports : any + + exports.a = 1 +>exports.a = 1 : 1 +>exports.a : any +>exports : any +>a : any +>1 : 1 +} + +function f10() { +>f10 : () => void + + let exports = {} +>exports : { a: number; } +>{} : { a: number; } + + exports.a = 1 +>exports.a = 1 : 1 +>exports.a : number +>exports : { a: number; } +>a : number +>1 : 1 +} + +function f11() { +>f11 : () => void + + let { exports } = { exports: { a: 0 } } +>exports : { a: number; } +>{ exports: { a: 0 } } : { exports: { a: number; }; } +>exports : { a: number; } +>{ a: 0 } : { a: number; } +>a : number +>0 : 0 + + exports.a = 1 +>exports.a = 1 : 1 +>exports.a : number +>exports : { a: number; } +>a : number +>1 : 1 +} + +function f12() { +>f12 : () => void + + let exports = {} +>exports : { a: number; } +>{} : { a: number; } + + while (true) { +>true : true + + exports.a = 1 +>exports.a = 1 : 1 +>exports.a : number +>exports : { a: number; } +>a : number +>1 : 1 + } +} + +function f13() { +>f13 : () => void + + let exports = { a: 0 } +>exports : { a: number; } +>{ a: 0 } : { a: number; } +>a : number +>0 : 0 + + function g() { +>g : () => void + + exports.a = 1 +>exports.a = 1 : 1 +>exports.a : number +>exports : { a: number; } +>a : number +>1 : 1 + } +} + +function f14() { +>f14 : () => void + + let exports = { a: 0 } +>exports : { a: number; } +>{ a: 0 } : { a: number; } +>a : number +>0 : 0 + + const g = () => { +>g : () => void +>() => { exports.a = 1 } : () => void + + exports.a = 1 +>exports.a = 1 : 1 +>exports.a : number +>exports : { a: number; } +>a : number +>1 : 1 + } +} + +function f15() { +>f15 : () => void + + const exports = {} +>exports : { a: number; } +>{} : { a: number; } + + exports.a = 1 +>exports.a = 1 : 1 +>exports.a : number +>exports : { a: number; } +>a : number +>1 : 1 +} + +function f16() { +>f16 : () => void + + var exports = {} +>exports : { a: number; } +>{} : { a: number; } + + exports.a = 1 +>exports.a = 1 : 1 +>exports.a : number +>exports : { a: number; } +>a : number +>1 : 1 +} + +function f17() { +>f17 : () => void + + function exports() {} +>exports : { (): void; a: number; } + + exports.a = 1 +>exports.a = 1 : 1 +>exports.a : number +>exports : { (): void; a: number; } +>a : number +>1 : 1 +} + +function f18() { +>f18 : () => void + + class exports {} +>exports : exports + + exports.a = 1 +>exports.a = 1 : 1 +>exports.a : number +>exports : typeof exports +>a : number +>1 : 1 +} + +function f19() { +>f19 : () => void + + for (const exports of [{ a: 0 }]) { +>exports : { a: number; } +>[{ a: 0 }] : { a: number; }[] +>{ a: 0 } : { a: number; } +>a : number +>0 : 0 + + exports.a = 1 +>exports.a = 1 : 1 +>exports.a : number +>exports : { a: number; } +>a : number +>1 : 1 + } +} + +function f20() { +>f20 : () => void + + try { + } + catch (/** @type {any} */ exports) { +>exports : any + + exports.a = 1 +>exports.a = 1 : 1 +>exports.a : any +>exports : any +>a : any +>1 : 1 + } +} + diff --git a/testdata/baselines/reference/compiler/shadowedModuleIdentifier.js b/testdata/baselines/reference/compiler/shadowedModuleIdentifier.js new file mode 100644 index 00000000000..938b2b10764 --- /dev/null +++ b/testdata/baselines/reference/compiler/shadowedModuleIdentifier.js @@ -0,0 +1,165 @@ +//// [tests/cases/compiler/shadowedModuleIdentifier.ts] //// + +//// [main.js] +// Each `module.exports` assignment in this file is supposed to reference a `module` local. +// If it doesn't, the `module.exports` assignment will conflict with the ESM export below. + +export const foo = 1 + +function f1(/** @type {any} */ module) { + module.exports = 1 +} + +function f2(/** @type {any} */ { module }) { + module.exports = 1 +} + +function f3(/** @type {any} */ { x: module }) { + module.exports = 1 +} + +function f4(/** @type {any} */ [module]) { + module.exports = 1 +} + +function f10() { + let module = {} + module.exports = 1 +} + +function f11() { + let { module } = { module: { exports: 0 } } + module.exports = 1 +} + +function f12() { + let module = {} + while (true) { + module.exports = 1 + } +} + +function f13() { + let module = { exports: 0 } + function g() { + module.exports = 1 + } +} + +function f14() { + let module = { exports: 0 } + const g = () => { + module.exports = 1 + } +} + +function f15() { + const module = {} + module.exports = 1 +} + +function f16() { + var module = {} + module.exports = 1 +} + +function f17() { + function module() {} + module.exports = 1 +} + +function f18() { + class module {} + module.exports = 1 +} + +function f19() { + for (const module of [{ exports: 0 }]) { + module.exports = 1 + } +} + +function f20() { + try { + } + catch (/** @type {any} */ module) { + module.exports = 1 + } +} + + +//// [main.js] +// Each `module.exports` assignment in this file is supposed to reference a `module` local. +// If it doesn't, the `module.exports` assignment will conflict with the ESM export below. +export const foo = 1; +function f1(/** @type {any} */ module) { + module.exports = 1; +} +function f2(/** @type {any} */ { module }) { + module.exports = 1; +} +function f3(/** @type {any} */ { x: module }) { + module.exports = 1; +} +function f4(/** @type {any} */ [module]) { + module.exports = 1; +} +function f10() { + let module = {}; + module.exports = 1; +} +function f11() { + let { module } = { module: { exports: 0 } }; + module.exports = 1; +} +function f12() { + let module = {}; + while (true) { + module.exports = 1; + } +} +function f13() { + let module = { exports: 0 }; + function g() { + module.exports = 1; + } +} +function f14() { + let module = { exports: 0 }; + const g = () => { + module.exports = 1; + }; +} +function f15() { + const module = {}; + module.exports = 1; +} +function f16() { + var module = {}; + module.exports = 1; +} +function f17() { + function module() { } + module.exports = 1; +} +function f18() { + class module { + } + module.exports = 1; +} +function f19() { + for (const module of [{ exports: 0 }]) { + module.exports = 1; + } +} +function f20() { + try { + } + catch ( /** @type {any} */module) { + module.exports = 1; + } +} + + +//// [main.d.ts] +export declare const foo = 1; diff --git a/testdata/baselines/reference/compiler/shadowedModuleIdentifier.symbols b/testdata/baselines/reference/compiler/shadowedModuleIdentifier.symbols new file mode 100644 index 00000000000..b9fd26a1589 --- /dev/null +++ b/testdata/baselines/reference/compiler/shadowedModuleIdentifier.symbols @@ -0,0 +1,190 @@ +//// [tests/cases/compiler/shadowedModuleIdentifier.ts] //// + +=== main.js === +// Each `module.exports` assignment in this file is supposed to reference a `module` local. +// If it doesn't, the `module.exports` assignment will conflict with the ESM export below. + +export const foo = 1 +>foo : Symbol(foo, Decl(main.js, 3, 12)) + +function f1(/** @type {any} */ module) { +>f1 : Symbol(f1, Decl(main.js, 3, 20)) +>module : Symbol(module, Decl(main.js, 5, 12)) + + module.exports = 1 +>module : Symbol(module, Decl(main.js, 5, 12)) +} + +function f2(/** @type {any} */ { module }) { +>f2 : Symbol(f2, Decl(main.js, 7, 1)) +>module : Symbol(module, Decl(main.js, 9, 32)) + + module.exports = 1 +>module : Symbol(module, Decl(main.js, 9, 32)) +} + +function f3(/** @type {any} */ { x: module }) { +>f3 : Symbol(f3, Decl(main.js, 11, 1)) +>module : Symbol(module, Decl(main.js, 13, 32)) + + module.exports = 1 +>module : Symbol(module, Decl(main.js, 13, 32)) +} + +function f4(/** @type {any} */ [module]) { +>f4 : Symbol(f4, Decl(main.js, 15, 1)) +>module : Symbol(module, Decl(main.js, 17, 32)) + + module.exports = 1 +>module : Symbol(module, Decl(main.js, 17, 32)) +} + +function f10() { +>f10 : Symbol(f10, Decl(main.js, 19, 1)) + + let module = {} +>module : Symbol(module, Decl(main.js, 22, 7)) + + module.exports = 1 +>module.exports : Symbol(exports, Decl(main.js, 22, 19)) +>module : Symbol(module, Decl(main.js, 22, 7)) +>exports : Symbol(exports, Decl(main.js, 22, 19)) +} + +function f11() { +>f11 : Symbol(f11, Decl(main.js, 24, 1)) + + let { module } = { module: { exports: 0 } } +>module : Symbol(module, Decl(main.js, 27, 9)) +>module : Symbol(module, Decl(main.js, 27, 22)) +>exports : Symbol(exports, Decl(main.js, 27, 32)) + + module.exports = 1 +>module.exports : Symbol(exports, Decl(main.js, 27, 32)) +>module : Symbol(module, Decl(main.js, 27, 9)) +>exports : Symbol(exports, Decl(main.js, 27, 32)) +} + +function f12() { +>f12 : Symbol(f12, Decl(main.js, 29, 1)) + + let module = {} +>module : Symbol(module, Decl(main.js, 32, 7)) + + while (true) { + module.exports = 1 +>module.exports : Symbol(exports, Decl(main.js, 33, 18)) +>module : Symbol(module, Decl(main.js, 32, 7)) +>exports : Symbol(exports, Decl(main.js, 33, 18)) + } +} + +function f13() { +>f13 : Symbol(f13, Decl(main.js, 36, 1)) + + let module = { exports: 0 } +>module : Symbol(module, Decl(main.js, 39, 7)) +>exports : Symbol(exports, Decl(main.js, 39, 18)) + + function g() { +>g : Symbol(g, Decl(main.js, 39, 31)) + + module.exports = 1 +>module.exports : Symbol(exports, Decl(main.js, 39, 18)) +>module : Symbol(module, Decl(main.js, 39, 7)) +>exports : Symbol(exports, Decl(main.js, 39, 18)) + } +} + +function f14() { +>f14 : Symbol(f14, Decl(main.js, 43, 1)) + + let module = { exports: 0 } +>module : Symbol(module, Decl(main.js, 46, 7)) +>exports : Symbol(exports, Decl(main.js, 46, 18)) + + const g = () => { +>g : Symbol(g, Decl(main.js, 47, 9)) + + module.exports = 1 +>module.exports : Symbol(exports, Decl(main.js, 46, 18)) +>module : Symbol(module, Decl(main.js, 46, 7)) +>exports : Symbol(exports, Decl(main.js, 46, 18)) + } +} + +function f15() { +>f15 : Symbol(f15, Decl(main.js, 50, 1)) + + const module = {} +>module : Symbol(module, Decl(main.js, 53, 9)) + + module.exports = 1 +>module.exports : Symbol(exports, Decl(main.js, 53, 21)) +>module : Symbol(module, Decl(main.js, 53, 9)) +>exports : Symbol(exports, Decl(main.js, 53, 21)) +} + +function f16() { +>f16 : Symbol(f16, Decl(main.js, 55, 1)) + + var module = {} +>module : Symbol(module, Decl(main.js, 58, 7)) + + module.exports = 1 +>module.exports : Symbol(exports, Decl(main.js, 58, 19)) +>module : Symbol(module, Decl(main.js, 58, 7)) +>exports : Symbol(exports, Decl(main.js, 58, 19)) +} + +function f17() { +>f17 : Symbol(f17, Decl(main.js, 60, 1)) + + function module() {} +>module : Symbol(module, Decl(main.js, 62, 16)) + + module.exports = 1 +>module.exports : Symbol(module.exports, Decl(main.js, 63, 24)) +>module : Symbol(module, Decl(main.js, 62, 16)) +>exports : Symbol(module.exports, Decl(main.js, 63, 24)) +} + +function f18() { +>f18 : Symbol(f18, Decl(main.js, 65, 1)) + + class module {} +>module : Symbol(module, Decl(main.js, 67, 16)) + + module.exports = 1 +>module.exports : Symbol(module.exports, Decl(main.js, 68, 19)) +>module : Symbol(module, Decl(main.js, 67, 16)) +>exports : Symbol(module.exports, Decl(main.js, 68, 19)) +} + +function f19() { +>f19 : Symbol(f19, Decl(main.js, 70, 1)) + + for (const module of [{ exports: 0 }]) { +>module : Symbol(module, Decl(main.js, 73, 14)) +>exports : Symbol(exports, Decl(main.js, 73, 27)) + + module.exports = 1 +>module.exports : Symbol(exports, Decl(main.js, 73, 27)) +>module : Symbol(module, Decl(main.js, 73, 14)) +>exports : Symbol(exports, Decl(main.js, 73, 27)) + } +} + +function f20() { +>f20 : Symbol(f20, Decl(main.js, 76, 1)) + + try { + } + catch (/** @type {any} */ module) { +>module : Symbol(module, Decl(main.js, 81, 11)) + + module.exports = 1 +>module : Symbol(module, Decl(main.js, 81, 11)) + } +} + diff --git a/testdata/baselines/reference/compiler/shadowedModuleIdentifier.types b/testdata/baselines/reference/compiler/shadowedModuleIdentifier.types new file mode 100644 index 00000000000..e19c4077a96 --- /dev/null +++ b/testdata/baselines/reference/compiler/shadowedModuleIdentifier.types @@ -0,0 +1,249 @@ +//// [tests/cases/compiler/shadowedModuleIdentifier.ts] //// + +=== main.js === +// Each `module.exports` assignment in this file is supposed to reference a `module` local. +// If it doesn't, the `module.exports` assignment will conflict with the ESM export below. + +export const foo = 1 +>foo : 1 +>1 : 1 + +function f1(/** @type {any} */ module) { +>f1 : (module: any) => void +>module : any + + module.exports = 1 +>module.exports = 1 : 1 +>module.exports : any +>module : any +>exports : any +>1 : 1 +} + +function f2(/** @type {any} */ { module }) { +>f2 : ({ module }: any) => void +>module : any + + module.exports = 1 +>module.exports = 1 : 1 +>module.exports : any +>module : any +>exports : any +>1 : 1 +} + +function f3(/** @type {any} */ { x: module }) { +>f3 : ({ x: module }: any) => void +>x : any +>module : any + + module.exports = 1 +>module.exports = 1 : 1 +>module.exports : any +>module : any +>exports : any +>1 : 1 +} + +function f4(/** @type {any} */ [module]) { +>f4 : ([module]: any) => void +>module : any + + module.exports = 1 +>module.exports = 1 : 1 +>module.exports : any +>module : any +>exports : any +>1 : 1 +} + +function f10() { +>f10 : () => void + + let module = {} +>module : { exports: number; } +>{} : { exports: number; } + + module.exports = 1 +>module.exports = 1 : 1 +>module.exports : number +>module : { exports: number; } +>exports : number +>1 : 1 +} + +function f11() { +>f11 : () => void + + let { module } = { module: { exports: 0 } } +>module : { exports: number; } +>{ module: { exports: 0 } } : { module: { exports: number; }; } +>module : { exports: number; } +>{ exports: 0 } : { exports: number; } +>exports : number +>0 : 0 + + module.exports = 1 +>module.exports = 1 : 1 +>module.exports : number +>module : { exports: number; } +>exports : number +>1 : 1 +} + +function f12() { +>f12 : () => void + + let module = {} +>module : { exports: number; } +>{} : { exports: number; } + + while (true) { +>true : true + + module.exports = 1 +>module.exports = 1 : 1 +>module.exports : number +>module : { exports: number; } +>exports : number +>1 : 1 + } +} + +function f13() { +>f13 : () => void + + let module = { exports: 0 } +>module : { exports: number; } +>{ exports: 0 } : { exports: number; } +>exports : number +>0 : 0 + + function g() { +>g : () => void + + module.exports = 1 +>module.exports = 1 : 1 +>module.exports : number +>module : { exports: number; } +>exports : number +>1 : 1 + } +} + +function f14() { +>f14 : () => void + + let module = { exports: 0 } +>module : { exports: number; } +>{ exports: 0 } : { exports: number; } +>exports : number +>0 : 0 + + const g = () => { +>g : () => void +>() => { module.exports = 1 } : () => void + + module.exports = 1 +>module.exports = 1 : 1 +>module.exports : number +>module : { exports: number; } +>exports : number +>1 : 1 + } +} + +function f15() { +>f15 : () => void + + const module = {} +>module : { exports: number; } +>{} : { exports: number; } + + module.exports = 1 +>module.exports = 1 : 1 +>module.exports : number +>module : { exports: number; } +>exports : number +>1 : 1 +} + +function f16() { +>f16 : () => void + + var module = {} +>module : { exports: number; } +>{} : { exports: number; } + + module.exports = 1 +>module.exports = 1 : 1 +>module.exports : number +>module : { exports: number; } +>exports : number +>1 : 1 +} + +function f17() { +>f17 : () => void + + function module() {} +>module : { (): void; exports: number; } + + module.exports = 1 +>module.exports = 1 : 1 +>module.exports : number +>module : { (): void; exports: number; } +>exports : number +>1 : 1 +} + +function f18() { +>f18 : () => void + + class module {} +>module : module + + module.exports = 1 +>module.exports = 1 : 1 +>module.exports : number +>module : typeof module +>exports : number +>1 : 1 +} + +function f19() { +>f19 : () => void + + for (const module of [{ exports: 0 }]) { +>module : { exports: number; } +>[{ exports: 0 }] : { exports: number; }[] +>{ exports: 0 } : { exports: number; } +>exports : number +>0 : 0 + + module.exports = 1 +>module.exports = 1 : 1 +>module.exports : number +>module : { exports: number; } +>exports : number +>1 : 1 + } +} + +function f20() { +>f20 : () => void + + try { + } + catch (/** @type {any} */ module) { +>module : any + + module.exports = 1 +>module.exports = 1 : 1 +>module.exports : any +>module : any +>exports : any +>1 : 1 + } +} + diff --git a/testdata/tests/cases/compiler/esModuleWithShadowedModuleIdentifier.ts b/testdata/tests/cases/compiler/esModuleWithShadowedModuleIdentifier.ts new file mode 100644 index 00000000000..5b31dbde144 --- /dev/null +++ b/testdata/tests/cases/compiler/esModuleWithShadowedModuleIdentifier.ts @@ -0,0 +1,16 @@ +// @allowJs: true +// @noEmit: true + +// https://github.com/microsoft/typescript-go/issues/2656 + +// @filename: dep.js +function something(module) { + module.exports = 8; +} + +export default 7; + +// @filename: main.ts +import DefaultExport from "./dep.js"; + +export default 3 + DefaultExport; diff --git a/testdata/tests/cases/compiler/shadowedExportsIdentifier.ts b/testdata/tests/cases/compiler/shadowedExportsIdentifier.ts new file mode 100644 index 00000000000..77f67cf58ac --- /dev/null +++ b/testdata/tests/cases/compiler/shadowedExportsIdentifier.ts @@ -0,0 +1,91 @@ +// @checkJs: true +// @declaration: true +// @outDir: ./out + +// @filename: main.js + +// Each `exports.a` assignment in this file is supposed to reference an `exports` local. +// If it doesn't, the `exports.a` assignment will conflict with the ESM export below. + +export const foo = 1 + +function f1(/** @type {any} */ exports) { + exports.a = 1 +} + +function f2(/** @type {any} */ { exports }) { + exports.a = 1 +} + +function f3(/** @type {any} */ { x: exports }) { + exports.a = 1 +} + +function f4(/** @type {any} */ [exports]) { + exports.a = 1 +} + +function f10() { + let exports = {} + exports.a = 1 +} + +function f11() { + let { exports } = { exports: { a: 0 } } + exports.a = 1 +} + +function f12() { + let exports = {} + while (true) { + exports.a = 1 + } +} + +function f13() { + let exports = { a: 0 } + function g() { + exports.a = 1 + } +} + +function f14() { + let exports = { a: 0 } + const g = () => { + exports.a = 1 + } +} + +function f15() { + const exports = {} + exports.a = 1 +} + +function f16() { + var exports = {} + exports.a = 1 +} + +function f17() { + function exports() {} + exports.a = 1 +} + +function f18() { + class exports {} + exports.a = 1 +} + +function f19() { + for (const exports of [{ a: 0 }]) { + exports.a = 1 + } +} + +function f20() { + try { + } + catch (/** @type {any} */ exports) { + exports.a = 1 + } +} diff --git a/testdata/tests/cases/compiler/shadowedModuleIdentifier.ts b/testdata/tests/cases/compiler/shadowedModuleIdentifier.ts new file mode 100644 index 00000000000..cd13658289b --- /dev/null +++ b/testdata/tests/cases/compiler/shadowedModuleIdentifier.ts @@ -0,0 +1,91 @@ +// @checkJs: true +// @declaration: true +// @outDir: ./out + +// @filename: main.js + +// Each `module.exports` assignment in this file is supposed to reference a `module` local. +// If it doesn't, the `module.exports` assignment will conflict with the ESM export below. + +export const foo = 1 + +function f1(/** @type {any} */ module) { + module.exports = 1 +} + +function f2(/** @type {any} */ { module }) { + module.exports = 1 +} + +function f3(/** @type {any} */ { x: module }) { + module.exports = 1 +} + +function f4(/** @type {any} */ [module]) { + module.exports = 1 +} + +function f10() { + let module = {} + module.exports = 1 +} + +function f11() { + let { module } = { module: { exports: 0 } } + module.exports = 1 +} + +function f12() { + let module = {} + while (true) { + module.exports = 1 + } +} + +function f13() { + let module = { exports: 0 } + function g() { + module.exports = 1 + } +} + +function f14() { + let module = { exports: 0 } + const g = () => { + module.exports = 1 + } +} + +function f15() { + const module = {} + module.exports = 1 +} + +function f16() { + var module = {} + module.exports = 1 +} + +function f17() { + function module() {} + module.exports = 1 +} + +function f18() { + class module {} + module.exports = 1 +} + +function f19() { + for (const module of [{ exports: 0 }]) { + module.exports = 1 + } +} + +function f20() { + try { + } + catch (/** @type {any} */ module) { + module.exports = 1 + } +} From f7c5801c9b73ed756a302fc88cae0f0a12a30dff Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 5 Apr 2026 12:30:20 -0400 Subject: [PATCH 5/8] Check shadowing for both `exports.xxx` and `module.exports.xxx` --- internal/parser/reparser.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/parser/reparser.go b/internal/parser/reparser.go index 08009fed129..438b4734938 100644 --- a/internal/parser/reparser.go +++ b/internal/parser/reparser.go @@ -42,8 +42,10 @@ func (p *Parser) reparseCommonJS(node *ast.Node, jsdoc []*ast.Node) { } case ast.JSDeclarationKindExportsProperty: // TODO: Name can sometimes be a string literal, so downstream code needs to handle this - // Reparse a CommonJSExport if `exports` identifier is not shadowed - if p.shadowFlags&ShadowFlagsExports == 0 { + // Reparse a CommonJSExport if `exports` identifier is not shadowed in `exports.xxx` or + // `module` identifier is not shadowed in `module.exports.xxx` + shadowFlag := core.IfElse(ast.IsIdentifier(expr.AsBinaryExpression().Left.Expression()), ShadowFlagsExports, ShadowFlagsModule) + if p.shadowFlags&shadowFlag == 0 { export = p.factory.NewCommonJSExport( nil, p.factory.DeepCloneReparse(ast.GetElementOrPropertyAccessName(expr.AsBinaryExpression().Left)), From 6b23368dffd691c2e96fe8ff55500d49a160963f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 5 Apr 2026 12:30:52 -0400 Subject: [PATCH 6/8] Save and restore shadowFlags in arrow function parsing --- internal/parser/parser.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/internal/parser/parser.go b/internal/parser/parser.go index c70b92aeba0..de2fa7fb763 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -64,8 +64,8 @@ const ( type ShadowFlags int32 const ( - ShadowFlagsModule = 1 << iota // `module` identifier is shadowed - ShadowFlagsExports // `exports` identifier is shadowed + ShadowFlagsModule ShadowFlags = 1 << iota // `module` identifier is shadowed + ShadowFlagsExports // `exports` identifier is shadowed ) type Parser struct { @@ -346,6 +346,7 @@ func (p *Parser) parseErrorAtRange(loc core.TextRange, message *diagnostics.Mess type ParserState struct { scannerState scanner.ScannerState contextFlags ast.NodeFlags + ShadowFlags ShadowFlags diagnosticsLen int jsDiagnosticsLen int jsdocInfosLen int @@ -358,6 +359,7 @@ func (p *Parser) mark() ParserState { return ParserState{ scannerState: p.scanner.Mark(), contextFlags: p.contextFlags, + ShadowFlags: p.shadowFlags, diagnosticsLen: len(p.diagnostics), jsDiagnosticsLen: len(p.jsDiagnostics), jsdocInfosLen: len(p.jsdocInfos), @@ -371,6 +373,7 @@ func (p *Parser) rewind(state ParserState) { p.scanner.Rewind(state.scannerState) p.token = p.scanner.Token() p.contextFlags = state.contextFlags + p.shadowFlags = state.ShadowFlags p.diagnostics = p.diagnostics[0:state.diagnosticsLen] p.jsDiagnostics = p.jsDiagnostics[0:state.jsDiagnosticsLen] p.jsdocInfos = p.jsdocInfos[0:state.jsdocInfosLen] @@ -4391,6 +4394,13 @@ func (p *Parser) tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInA } func (p *Parser) parseParenthesizedArrowFunctionExpression(allowAmbiguity bool, allowReturnTypeInArrowFunction bool) *ast.Node { + saveShadowFlags := p.shadowFlags + result := p.parseParenthesizedArrowFunctionExpressionWorker(allowAmbiguity, allowReturnTypeInArrowFunction) + p.shadowFlags = saveShadowFlags + return result +} + +func (p *Parser) parseParenthesizedArrowFunctionExpressionWorker(allowAmbiguity bool, allowReturnTypeInArrowFunction bool) *ast.Node { pos := p.nodePos() jsdoc := p.jsdocScannerInfo() modifiers := p.parseModifiersForArrowFunction() @@ -4591,10 +4601,13 @@ func (p *Parser) nextIsUnParenthesizedAsyncArrowFunction() bool { func (p *Parser) parseSimpleArrowFunctionExpression(pos int, identifier *ast.Node, allowReturnTypeInArrowFunction bool, jsdoc jsdocScannerInfo, asyncModifier *ast.ModifierList) *ast.Node { debug.Assert(p.token == ast.KindEqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>") + saveShadowFlags := p.shadowFlags parameter := p.finishNode(p.factory.NewParameterDeclaration(nil /*modifiers*/, nil /*dotDotDotToken*/, identifier, nil /*questionToken*/, nil /*typeNode*/, nil /*initializer*/), identifier.Pos()) + p.updateShadowFlags(identifier) parameters := p.newNodeList(parameter.Loc, []*ast.Node{parameter}) equalsGreaterThanToken := p.parseExpectedToken(ast.KindEqualsGreaterThanToken) body := p.parseArrowFunctionExpressionBody(asyncModifier != nil /*isAsync*/, allowReturnTypeInArrowFunction) + p.shadowFlags = saveShadowFlags result := p.finishNode(p.factory.NewArrowFunction(asyncModifier, nil /*typeParameters*/, parameters, nil /*returnType*/, nil /*fullSignature*/, equalsGreaterThanToken, body), pos) p.withJSDoc(result, jsdoc) return result From a71867d58bdd932df8f20a341a9a0dc83466032f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 5 Apr 2026 15:50:02 -0400 Subject: [PATCH 7/8] Add more tests --- .../compiler/shadowedModuleIdentifier.js | 52 +++++ .../compiler/shadowedModuleIdentifier.symbols | 177 ++++++++++++------ .../compiler/shadowedModuleIdentifier.types | 92 +++++++++ .../compiler/shadowedModuleIdentifier.ts | 29 +++ 4 files changed, 290 insertions(+), 60 deletions(-) diff --git a/testdata/baselines/reference/compiler/shadowedModuleIdentifier.js b/testdata/baselines/reference/compiler/shadowedModuleIdentifier.js index 938b2b10764..e51862428ec 100644 --- a/testdata/baselines/reference/compiler/shadowedModuleIdentifier.js +++ b/testdata/baselines/reference/compiler/shadowedModuleIdentifier.js @@ -22,6 +22,22 @@ function f4(/** @type {any} */ [module]) { module.exports = 1 } +function f5(/** @type {any} */ module) { + module.exports.a = 1 +} + +function f6(/** @type {any} */ { module }) { + module.exports.a = 1 +} + +function f7(/** @type {any} */ { x: module }) { + module.exports.a = 1 +} + +function f8(/** @type {any} */ [module]) { + module.exports.a = 1 +} + function f10() { let module = {} module.exports = 1 @@ -86,6 +102,19 @@ function f20() { module.exports = 1 } } + +function f21() { + /** @param {any} module */ + const g = module => { + module.exports = 1 + } +} + +function f22() { + const g = (/** @type {any} */ module) => { + module.exports = 1 + } +} //// [main.js] @@ -104,6 +133,18 @@ function f3(/** @type {any} */ { x: module }) { function f4(/** @type {any} */ [module]) { module.exports = 1; } +function f5(/** @type {any} */ module) { + module.exports.a = 1; +} +function f6(/** @type {any} */ { module }) { + module.exports.a = 1; +} +function f7(/** @type {any} */ { x: module }) { + module.exports.a = 1; +} +function f8(/** @type {any} */ [module]) { + module.exports.a = 1; +} function f10() { let module = {}; module.exports = 1; @@ -159,6 +200,17 @@ function f20() { module.exports = 1; } } +function f21() { + /** @param {any} module */ + const g = module => { + module.exports = 1; + }; +} +function f22() { + const g = (/** @type {any} */ module) => { + module.exports = 1; + }; +} //// [main.d.ts] diff --git a/testdata/baselines/reference/compiler/shadowedModuleIdentifier.symbols b/testdata/baselines/reference/compiler/shadowedModuleIdentifier.symbols index b9fd26a1589..4632d3b3698 100644 --- a/testdata/baselines/reference/compiler/shadowedModuleIdentifier.symbols +++ b/testdata/baselines/reference/compiler/shadowedModuleIdentifier.symbols @@ -39,152 +39,209 @@ function f4(/** @type {any} */ [module]) { >module : Symbol(module, Decl(main.js, 17, 32)) } +function f5(/** @type {any} */ module) { +>f5 : Symbol(f5, Decl(main.js, 19, 1)) +>module : Symbol(module, Decl(main.js, 21, 12)) + + module.exports.a = 1 +>module : Symbol(module, Decl(main.js, 21, 12)) +} + +function f6(/** @type {any} */ { module }) { +>f6 : Symbol(f6, Decl(main.js, 23, 1)) +>module : Symbol(module, Decl(main.js, 25, 32)) + + module.exports.a = 1 +>module : Symbol(module, Decl(main.js, 25, 32)) +} + +function f7(/** @type {any} */ { x: module }) { +>f7 : Symbol(f7, Decl(main.js, 27, 1)) +>module : Symbol(module, Decl(main.js, 29, 32)) + + module.exports.a = 1 +>module : Symbol(module, Decl(main.js, 29, 32)) +} + +function f8(/** @type {any} */ [module]) { +>f8 : Symbol(f8, Decl(main.js, 31, 1)) +>module : Symbol(module, Decl(main.js, 33, 32)) + + module.exports.a = 1 +>module : Symbol(module, Decl(main.js, 33, 32)) +} + function f10() { ->f10 : Symbol(f10, Decl(main.js, 19, 1)) +>f10 : Symbol(f10, Decl(main.js, 35, 1)) let module = {} ->module : Symbol(module, Decl(main.js, 22, 7)) +>module : Symbol(module, Decl(main.js, 38, 7)) module.exports = 1 ->module.exports : Symbol(exports, Decl(main.js, 22, 19)) ->module : Symbol(module, Decl(main.js, 22, 7)) ->exports : Symbol(exports, Decl(main.js, 22, 19)) +>module.exports : Symbol(exports, Decl(main.js, 38, 19)) +>module : Symbol(module, Decl(main.js, 38, 7)) +>exports : Symbol(exports, Decl(main.js, 38, 19)) } function f11() { ->f11 : Symbol(f11, Decl(main.js, 24, 1)) +>f11 : Symbol(f11, Decl(main.js, 40, 1)) let { module } = { module: { exports: 0 } } ->module : Symbol(module, Decl(main.js, 27, 9)) ->module : Symbol(module, Decl(main.js, 27, 22)) ->exports : Symbol(exports, Decl(main.js, 27, 32)) +>module : Symbol(module, Decl(main.js, 43, 9)) +>module : Symbol(module, Decl(main.js, 43, 22)) +>exports : Symbol(exports, Decl(main.js, 43, 32)) module.exports = 1 ->module.exports : Symbol(exports, Decl(main.js, 27, 32)) ->module : Symbol(module, Decl(main.js, 27, 9)) ->exports : Symbol(exports, Decl(main.js, 27, 32)) +>module.exports : Symbol(exports, Decl(main.js, 43, 32)) +>module : Symbol(module, Decl(main.js, 43, 9)) +>exports : Symbol(exports, Decl(main.js, 43, 32)) } function f12() { ->f12 : Symbol(f12, Decl(main.js, 29, 1)) +>f12 : Symbol(f12, Decl(main.js, 45, 1)) let module = {} ->module : Symbol(module, Decl(main.js, 32, 7)) +>module : Symbol(module, Decl(main.js, 48, 7)) while (true) { module.exports = 1 ->module.exports : Symbol(exports, Decl(main.js, 33, 18)) ->module : Symbol(module, Decl(main.js, 32, 7)) ->exports : Symbol(exports, Decl(main.js, 33, 18)) +>module.exports : Symbol(exports, Decl(main.js, 49, 18)) +>module : Symbol(module, Decl(main.js, 48, 7)) +>exports : Symbol(exports, Decl(main.js, 49, 18)) } } function f13() { ->f13 : Symbol(f13, Decl(main.js, 36, 1)) +>f13 : Symbol(f13, Decl(main.js, 52, 1)) let module = { exports: 0 } ->module : Symbol(module, Decl(main.js, 39, 7)) ->exports : Symbol(exports, Decl(main.js, 39, 18)) +>module : Symbol(module, Decl(main.js, 55, 7)) +>exports : Symbol(exports, Decl(main.js, 55, 18)) function g() { ->g : Symbol(g, Decl(main.js, 39, 31)) +>g : Symbol(g, Decl(main.js, 55, 31)) module.exports = 1 ->module.exports : Symbol(exports, Decl(main.js, 39, 18)) ->module : Symbol(module, Decl(main.js, 39, 7)) ->exports : Symbol(exports, Decl(main.js, 39, 18)) +>module.exports : Symbol(exports, Decl(main.js, 55, 18)) +>module : Symbol(module, Decl(main.js, 55, 7)) +>exports : Symbol(exports, Decl(main.js, 55, 18)) } } function f14() { ->f14 : Symbol(f14, Decl(main.js, 43, 1)) +>f14 : Symbol(f14, Decl(main.js, 59, 1)) let module = { exports: 0 } ->module : Symbol(module, Decl(main.js, 46, 7)) ->exports : Symbol(exports, Decl(main.js, 46, 18)) +>module : Symbol(module, Decl(main.js, 62, 7)) +>exports : Symbol(exports, Decl(main.js, 62, 18)) const g = () => { ->g : Symbol(g, Decl(main.js, 47, 9)) +>g : Symbol(g, Decl(main.js, 63, 9)) module.exports = 1 ->module.exports : Symbol(exports, Decl(main.js, 46, 18)) ->module : Symbol(module, Decl(main.js, 46, 7)) ->exports : Symbol(exports, Decl(main.js, 46, 18)) +>module.exports : Symbol(exports, Decl(main.js, 62, 18)) +>module : Symbol(module, Decl(main.js, 62, 7)) +>exports : Symbol(exports, Decl(main.js, 62, 18)) } } function f15() { ->f15 : Symbol(f15, Decl(main.js, 50, 1)) +>f15 : Symbol(f15, Decl(main.js, 66, 1)) const module = {} ->module : Symbol(module, Decl(main.js, 53, 9)) +>module : Symbol(module, Decl(main.js, 69, 9)) module.exports = 1 ->module.exports : Symbol(exports, Decl(main.js, 53, 21)) ->module : Symbol(module, Decl(main.js, 53, 9)) ->exports : Symbol(exports, Decl(main.js, 53, 21)) +>module.exports : Symbol(exports, Decl(main.js, 69, 21)) +>module : Symbol(module, Decl(main.js, 69, 9)) +>exports : Symbol(exports, Decl(main.js, 69, 21)) } function f16() { ->f16 : Symbol(f16, Decl(main.js, 55, 1)) +>f16 : Symbol(f16, Decl(main.js, 71, 1)) var module = {} ->module : Symbol(module, Decl(main.js, 58, 7)) +>module : Symbol(module, Decl(main.js, 74, 7)) module.exports = 1 ->module.exports : Symbol(exports, Decl(main.js, 58, 19)) ->module : Symbol(module, Decl(main.js, 58, 7)) ->exports : Symbol(exports, Decl(main.js, 58, 19)) +>module.exports : Symbol(exports, Decl(main.js, 74, 19)) +>module : Symbol(module, Decl(main.js, 74, 7)) +>exports : Symbol(exports, Decl(main.js, 74, 19)) } function f17() { ->f17 : Symbol(f17, Decl(main.js, 60, 1)) +>f17 : Symbol(f17, Decl(main.js, 76, 1)) function module() {} ->module : Symbol(module, Decl(main.js, 62, 16)) +>module : Symbol(module, Decl(main.js, 78, 16)) module.exports = 1 ->module.exports : Symbol(module.exports, Decl(main.js, 63, 24)) ->module : Symbol(module, Decl(main.js, 62, 16)) ->exports : Symbol(module.exports, Decl(main.js, 63, 24)) +>module.exports : Symbol(module.exports, Decl(main.js, 79, 24)) +>module : Symbol(module, Decl(main.js, 78, 16)) +>exports : Symbol(module.exports, Decl(main.js, 79, 24)) } function f18() { ->f18 : Symbol(f18, Decl(main.js, 65, 1)) +>f18 : Symbol(f18, Decl(main.js, 81, 1)) class module {} ->module : Symbol(module, Decl(main.js, 67, 16)) +>module : Symbol(module, Decl(main.js, 83, 16)) module.exports = 1 ->module.exports : Symbol(module.exports, Decl(main.js, 68, 19)) ->module : Symbol(module, Decl(main.js, 67, 16)) ->exports : Symbol(module.exports, Decl(main.js, 68, 19)) +>module.exports : Symbol(module.exports, Decl(main.js, 84, 19)) +>module : Symbol(module, Decl(main.js, 83, 16)) +>exports : Symbol(module.exports, Decl(main.js, 84, 19)) } function f19() { ->f19 : Symbol(f19, Decl(main.js, 70, 1)) +>f19 : Symbol(f19, Decl(main.js, 86, 1)) for (const module of [{ exports: 0 }]) { ->module : Symbol(module, Decl(main.js, 73, 14)) ->exports : Symbol(exports, Decl(main.js, 73, 27)) +>module : Symbol(module, Decl(main.js, 89, 14)) +>exports : Symbol(exports, Decl(main.js, 89, 27)) module.exports = 1 ->module.exports : Symbol(exports, Decl(main.js, 73, 27)) ->module : Symbol(module, Decl(main.js, 73, 14)) ->exports : Symbol(exports, Decl(main.js, 73, 27)) +>module.exports : Symbol(exports, Decl(main.js, 89, 27)) +>module : Symbol(module, Decl(main.js, 89, 14)) +>exports : Symbol(exports, Decl(main.js, 89, 27)) } } function f20() { ->f20 : Symbol(f20, Decl(main.js, 76, 1)) +>f20 : Symbol(f20, Decl(main.js, 92, 1)) try { } catch (/** @type {any} */ module) { ->module : Symbol(module, Decl(main.js, 81, 11)) +>module : Symbol(module, Decl(main.js, 97, 11)) + + module.exports = 1 +>module : Symbol(module, Decl(main.js, 97, 11)) + } +} + +function f21() { +>f21 : Symbol(f21, Decl(main.js, 100, 1)) + + /** @param {any} module */ + const g = module => { +>g : Symbol(g, Decl(main.js, 104, 9)) +>module : Symbol(module, Decl(main.js, 104, 13)) + + module.exports = 1 +>module : Symbol(module, Decl(main.js, 104, 13)) + } +} + +function f22() { +>f22 : Symbol(f22, Decl(main.js, 107, 1)) + + const g = (/** @type {any} */ module) => { +>g : Symbol(g, Decl(main.js, 110, 9)) +>module : Symbol(module, Decl(main.js, 110, 15)) module.exports = 1 ->module : Symbol(module, Decl(main.js, 81, 11)) +>module : Symbol(module, Decl(main.js, 110, 15)) } } diff --git a/testdata/baselines/reference/compiler/shadowedModuleIdentifier.types b/testdata/baselines/reference/compiler/shadowedModuleIdentifier.types index e19c4077a96..5379855c447 100644 --- a/testdata/baselines/reference/compiler/shadowedModuleIdentifier.types +++ b/testdata/baselines/reference/compiler/shadowedModuleIdentifier.types @@ -57,6 +57,63 @@ function f4(/** @type {any} */ [module]) { >1 : 1 } +function f5(/** @type {any} */ module) { +>f5 : (module: any) => void +>module : any + + module.exports.a = 1 +>module.exports.a = 1 : 1 +>module.exports.a : any +>module.exports : any +>module : any +>exports : any +>a : any +>1 : 1 +} + +function f6(/** @type {any} */ { module }) { +>f6 : ({ module }: any) => void +>module : any + + module.exports.a = 1 +>module.exports.a = 1 : 1 +>module.exports.a : any +>module.exports : any +>module : any +>exports : any +>a : any +>1 : 1 +} + +function f7(/** @type {any} */ { x: module }) { +>f7 : ({ x: module }: any) => void +>x : any +>module : any + + module.exports.a = 1 +>module.exports.a = 1 : 1 +>module.exports.a : any +>module.exports : any +>module : any +>exports : any +>a : any +>1 : 1 +} + +function f8(/** @type {any} */ [module]) { +>f8 : ([module]: any) => void +>module : any + + module.exports.a = 1 +>module.exports.a = 1 : 1 +>module.exports.a : any +>module.exports : any +>module : any +>exports : any +>a : any +>1 : 1 +} + function f10() { >f10 : () => void @@ -247,3 +304,38 @@ function f20() { } } +function f21() { +>f21 : () => void + + /** @param {any} module */ + const g = module => { +>g : (module: any) => void +>module => { module.exports = 1 } : (module: any) => void +>module : any + + module.exports = 1 +>module.exports = 1 : 1 +>module.exports : any +>module : any +>exports : any +>1 : 1 + } +} + +function f22() { +>f22 : () => void + + const g = (/** @type {any} */ module) => { +>g : (module: any) => void +>(/** @type {any} */ module) => { module.exports = 1 } : (module: any) => void +>module : any + + module.exports = 1 +>module.exports = 1 : 1 +>module.exports : any +>module : any +>exports : any +>1 : 1 + } +} + diff --git a/testdata/tests/cases/compiler/shadowedModuleIdentifier.ts b/testdata/tests/cases/compiler/shadowedModuleIdentifier.ts index cd13658289b..6cfcf8a7b84 100644 --- a/testdata/tests/cases/compiler/shadowedModuleIdentifier.ts +++ b/testdata/tests/cases/compiler/shadowedModuleIdentifier.ts @@ -25,6 +25,22 @@ function f4(/** @type {any} */ [module]) { module.exports = 1 } +function f5(/** @type {any} */ module) { + module.exports.a = 1 +} + +function f6(/** @type {any} */ { module }) { + module.exports.a = 1 +} + +function f7(/** @type {any} */ { x: module }) { + module.exports.a = 1 +} + +function f8(/** @type {any} */ [module]) { + module.exports.a = 1 +} + function f10() { let module = {} module.exports = 1 @@ -89,3 +105,16 @@ function f20() { module.exports = 1 } } + +function f21() { + /** @param {any} module */ + const g = module => { + module.exports = 1 + } +} + +function f22() { + const g = (/** @type {any} */ module) => { + module.exports = 1 + } +} From a25f65e71a5a6b2fdac3778c941a4d899273d772 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 5 Apr 2026 17:24:05 -0400 Subject: [PATCH 8/8] ParserState.shadowFlags shouldn't be public --- internal/parser/parser.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/parser/parser.go b/internal/parser/parser.go index de2fa7fb763..edf3c5c3f44 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -346,7 +346,7 @@ func (p *Parser) parseErrorAtRange(loc core.TextRange, message *diagnostics.Mess type ParserState struct { scannerState scanner.ScannerState contextFlags ast.NodeFlags - ShadowFlags ShadowFlags + shadowFlags ShadowFlags diagnosticsLen int jsDiagnosticsLen int jsdocInfosLen int @@ -359,7 +359,7 @@ func (p *Parser) mark() ParserState { return ParserState{ scannerState: p.scanner.Mark(), contextFlags: p.contextFlags, - ShadowFlags: p.shadowFlags, + shadowFlags: p.shadowFlags, diagnosticsLen: len(p.diagnostics), jsDiagnosticsLen: len(p.jsDiagnostics), jsdocInfosLen: len(p.jsdocInfos), @@ -373,7 +373,7 @@ func (p *Parser) rewind(state ParserState) { p.scanner.Rewind(state.scannerState) p.token = p.scanner.Token() p.contextFlags = state.contextFlags - p.shadowFlags = state.ShadowFlags + p.shadowFlags = state.shadowFlags p.diagnostics = p.diagnostics[0:state.diagnosticsLen] p.jsDiagnostics = p.jsDiagnostics[0:state.jsDiagnosticsLen] p.jsdocInfos = p.jsdocInfos[0:state.jsdocInfosLen]