Skip to content

Commit ad2a074

Browse files
authored
Fix crash on js declaration emit of export assigned default augmented function (microsoft#40596)
* Fix crash on js declaration emit of export assigned default augmented function * {sp}
1 parent 83574ba commit ad2a074

File tree

5 files changed

+86
-8
lines changed

5 files changed

+86
-8
lines changed

src/compiler/checker.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6896,7 +6896,7 @@ namespace ts {
68966896
const name = unescapeLeadingUnderscores(symbol.escapedName);
68976897
const isExportEquals = name === InternalSymbolName.ExportEquals;
68986898
const isDefault = name === InternalSymbolName.Default;
6899-
const isExportAssignment = isExportEquals || isDefault;
6899+
const isExportAssignmentCompatibleSymbolName = isExportEquals || isDefault;
69006900
// synthesize export = ref
69016901
// ref should refer to either be a locally scoped symbol which we need to emit, or
69026902
// a reference to another namespace/module which we may need to emit an `import` statement for
@@ -6908,8 +6908,8 @@ namespace ts {
69086908
// In case `target` refers to a namespace member, look at the declaration and serialize the leftmost symbol in it
69096909
// eg, `namespace A { export class B {} }; exports = A.B;`
69106910
// Technically, this is all that's required in the case where the assignment is an entity name expression
6911-
const expr = isExportAssignment ? getExportAssignmentExpression(aliasDecl as ExportAssignment | BinaryExpression) : getPropertyAssignmentAliasLikeExpression(aliasDecl as ShorthandPropertyAssignment | PropertyAssignment | PropertyAccessExpression);
6912-
const first = isEntityNameExpression(expr) ? getFirstNonModuleExportsIdentifier(expr) : undefined;
6911+
const expr = aliasDecl && ((isExportAssignment(aliasDecl) || isBinaryExpression(aliasDecl)) ? getExportAssignmentExpression(aliasDecl) : getPropertyAssignmentAliasLikeExpression(aliasDecl as ShorthandPropertyAssignment | PropertyAssignment | PropertyAccessExpression));
6912+
const first = expr && isEntityNameExpression(expr) ? getFirstNonModuleExportsIdentifier(expr) : undefined;
69136913
const referenced = first && resolveEntityName(first, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, enclosingDeclaration);
69146914
if (referenced || target) {
69156915
includePrivateSymbol(referenced || target);
@@ -6922,7 +6922,7 @@ namespace ts {
69226922
// into the containing scope anyway, so we want to skip the visibility checks.
69236923
const oldTrack = context.tracker.trackSymbol;
69246924
context.tracker.trackSymbol = noop;
6925-
if (isExportAssignment) {
6925+
if (isExportAssignmentCompatibleSymbolName) {
69266926
results.push(factory.createExportAssignment(
69276927
/*decorators*/ undefined,
69286928
/*modifiers*/ undefined,
@@ -6931,11 +6931,11 @@ namespace ts {
69316931
));
69326932
}
69336933
else {
6934-
if (first === expr) {
6934+
if (first === expr && first) {
69356935
// serialize as `export {target as name}`
69366936
serializeExportSpecifier(name, idText(first));
69376937
}
6938-
else if (isClassExpression(expr)) {
6938+
else if (expr && isClassExpression(expr)) {
69396939
serializeExportSpecifier(name, getInternalSymbolName(target, symbolName(target)));
69406940
}
69416941
else {
@@ -6961,7 +6961,7 @@ namespace ts {
69616961
const typeToSerialize = getWidenedType(getTypeOfSymbol(getMergedSymbol(symbol)));
69626962
if (isTypeRepresentableAsFunctionNamespaceMerge(typeToSerialize, symbol)) {
69636963
// If there are no index signatures and `typeToSerialize` is an object type, emit as a namespace instead of a const
6964-
serializeAsFunctionNamespaceMerge(typeToSerialize, symbol, varName, isExportAssignment ? ModifierFlags.None : ModifierFlags.Export);
6964+
serializeAsFunctionNamespaceMerge(typeToSerialize, symbol, varName, isExportAssignmentCompatibleSymbolName ? ModifierFlags.None : ModifierFlags.Export);
69656965
}
69666966
else {
69676967
const statement = factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([
@@ -6974,7 +6974,7 @@ namespace ts {
69746974
: name === varName ? ModifierFlags.Export
69756975
: ModifierFlags.None);
69766976
}
6977-
if (isExportAssignment) {
6977+
if (isExportAssignmentCompatibleSymbolName) {
69786978
results.push(factory.createExportAssignment(
69796979
/*decorators*/ undefined,
69806980
/*modifiers*/ undefined,
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//// [index.js]
2+
function foo() {}
3+
4+
foo.foo = foo;
5+
foo.default = foo;
6+
module.exports = foo;
7+
8+
//// [index.js]
9+
function foo() { }
10+
foo.foo = foo;
11+
foo["default"] = foo;
12+
module.exports = foo;
13+
14+
15+
//// [index.d.ts]
16+
export = foo;
17+
declare function foo(): void;
18+
declare namespace foo {
19+
export { foo };
20+
export { foo as default };
21+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== tests/cases/conformance/jsdoc/declarations/index.js ===
2+
function foo() {}
3+
>foo : Symbol(foo, Decl(index.js, 0, 0), Decl(index.js, 0, 17), Decl(index.js, 2, 14))
4+
5+
foo.foo = foo;
6+
>foo.foo : Symbol(foo.foo, Decl(index.js, 0, 17))
7+
>foo : Symbol(foo, Decl(index.js, 0, 0), Decl(index.js, 0, 17), Decl(index.js, 2, 14))
8+
>foo : Symbol(foo.foo, Decl(index.js, 0, 17))
9+
>foo : Symbol(foo, Decl(index.js, 0, 0), Decl(index.js, 0, 17), Decl(index.js, 2, 14))
10+
11+
foo.default = foo;
12+
>foo.default : Symbol(foo.default, Decl(index.js, 2, 14))
13+
>foo : Symbol(foo, Decl(index.js, 0, 0), Decl(index.js, 0, 17), Decl(index.js, 2, 14))
14+
>default : Symbol(foo.default, Decl(index.js, 2, 14))
15+
>foo : Symbol(foo, Decl(index.js, 0, 0), Decl(index.js, 0, 17), Decl(index.js, 2, 14))
16+
17+
module.exports = foo;
18+
>module.exports : Symbol("tests/cases/conformance/jsdoc/declarations/index", Decl(index.js, 0, 0))
19+
>module : Symbol(export=, Decl(index.js, 3, 18))
20+
>exports : Symbol(export=, Decl(index.js, 3, 18))
21+
>foo : Symbol(foo, Decl(index.js, 0, 0), Decl(index.js, 0, 17), Decl(index.js, 2, 14))
22+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
=== tests/cases/conformance/jsdoc/declarations/index.js ===
2+
function foo() {}
3+
>foo : typeof foo
4+
5+
foo.foo = foo;
6+
>foo.foo = foo : typeof foo
7+
>foo.foo : typeof foo
8+
>foo : typeof foo
9+
>foo : typeof foo
10+
>foo : typeof foo
11+
12+
foo.default = foo;
13+
>foo.default = foo : typeof foo
14+
>foo.default : typeof foo
15+
>foo : typeof foo
16+
>default : typeof foo
17+
>foo : typeof foo
18+
19+
module.exports = foo;
20+
>module.exports = foo : typeof foo
21+
>module.exports : typeof foo
22+
>module : { "\"tests/cases/conformance/jsdoc/declarations/index\"": typeof foo; }
23+
>exports : typeof foo
24+
>foo : typeof foo
25+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// @allowJs: true
2+
// @checkJs: true
3+
// @outDir: ./out
4+
// @declaration: true
5+
// @filename: index.js
6+
function foo() {}
7+
8+
foo.foo = foo;
9+
foo.default = foo;
10+
module.exports = foo;

0 commit comments

Comments
 (0)