Skip to content

Commit a67ad06

Browse files
authored
Merge pull request microsoft#10239 from Microsoft/fix10193
Fix 10193: Compiler crash with decorator and two "export default"s
2 parents 44c475f + f195bd5 commit a67ad06

21 files changed

+280
-11
lines changed

src/compiler/binder.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -355,11 +355,24 @@ namespace ts {
355355
? Diagnostics.Cannot_redeclare_block_scoped_variable_0
356356
: Diagnostics.Duplicate_identifier_0;
357357

358-
forEach(symbol.declarations, declaration => {
359-
if (hasModifier(declaration, ModifierFlags.Default)) {
358+
if (symbol.declarations && symbol.declarations.length) {
359+
// If the current node is a default export of some sort, then check if
360+
// there are any other default exports that we need to error on.
361+
// We'll know whether we have other default exports depending on if `symbol` already has a declaration list set.
362+
if (isDefaultExport) {
360363
message = Diagnostics.A_module_cannot_have_multiple_default_exports;
361364
}
362-
});
365+
else {
366+
// This is to properly report an error in the case "export default { }" is after export default of class declaration or function declaration.
367+
// Error on multiple export default in the following case:
368+
// 1. multiple export default of class declaration or function declaration by checking NodeFlags.Default
369+
// 2. multiple export default of export assignment. This one doesn't have NodeFlags.Default on (as export default doesn't considered as modifiers)
370+
if (symbol.declarations && symbol.declarations.length &&
371+
(isDefaultExport || (node.kind === SyntaxKind.ExportAssignment && !(<ExportAssignment>node).isExportEquals))) {
372+
message = Diagnostics.A_module_cannot_have_multiple_default_exports;
373+
}
374+
}
375+
}
363376

364377
forEach(symbol.declarations, declaration => {
365378
file.bindDiagnostics.push(createDiagnosticForNode(declaration.name || declaration, message, getDisplayName(declaration)));
@@ -1944,12 +1957,15 @@ namespace ts {
19441957
bindAnonymousDeclaration(node, SymbolFlags.Alias, getDeclarationName(node));
19451958
}
19461959
else {
1960+
// An export default clause with an expression exports a value
1961+
// We want to exclude both class and function here, this is necessary to issue an error when there are both
1962+
// default export-assignment and default export function and class declaration.
19471963
const flags = node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(<ExportAssignment>node)
19481964
// An export default clause with an EntityNameExpression exports all meanings of that identifier
19491965
? SymbolFlags.Alias
19501966
// An export default clause with any other expression exports a value
19511967
: SymbolFlags.Property;
1952-
declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes);
1968+
declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.Property | SymbolFlags.AliasExcludes | SymbolFlags.Class | SymbolFlags.Function);
19531969
}
19541970
}
19551971

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1+
tests/cases/compiler/a.js(1,22): error TS2528: A module cannot have multiple default exports.
2+
tests/cases/compiler/a.js(3,1): error TS2528: A module cannot have multiple default exports.
13
tests/cases/compiler/a.js(3,16): error TS1109: Expression expected.
24

35

4-
==== tests/cases/compiler/a.js (1 errors) ====
6+
==== tests/cases/compiler/a.js (3 errors) ====
57
export default class a {
8+
~
9+
!!! error TS2528: A module cannot have multiple default exports.
610
}
711
export default var a = 10;
12+
~~~~~~~~~~~~~~
13+
!!! error TS2528: A module cannot have multiple default exports.
814
~~~
915
!!! error TS1109: Expression expected.

tests/baselines/reference/multipleDefaultExports01.errors.txt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
1-
tests/cases/conformance/es6/modules/m1.ts(2,22): error TS2323: Cannot redeclare exported variable 'default'.
21
tests/cases/conformance/es6/modules/m1.ts(2,22): error TS2528: A module cannot have multiple default exports.
32
tests/cases/conformance/es6/modules/m1.ts(6,25): error TS2528: A module cannot have multiple default exports.
4-
tests/cases/conformance/es6/modules/m1.ts(11,1): error TS2323: Cannot redeclare exported variable 'default'.
3+
tests/cases/conformance/es6/modules/m1.ts(11,1): error TS2528: A module cannot have multiple default exports.
54
tests/cases/conformance/es6/modules/m2.ts(3,1): error TS2348: Value of type 'typeof foo' is not callable. Did you mean to include 'new'?
65

76

8-
==== tests/cases/conformance/es6/modules/m1.ts (4 errors) ====
7+
==== tests/cases/conformance/es6/modules/m1.ts (3 errors) ====
98

109
export default class foo {
1110
~~~
12-
!!! error TS2323: Cannot redeclare exported variable 'default'.
13-
~~~
1411
!!! error TS2528: A module cannot have multiple default exports.
1512

1613
}
@@ -24,7 +21,7 @@ tests/cases/conformance/es6/modules/m2.ts(3,1): error TS2348: Value of type 'typ
2421
var x = 10;
2522
export default x;
2623
~~~~~~~~~~~~~~~~~
27-
!!! error TS2323: Cannot redeclare exported variable 'default'.
24+
!!! error TS2528: A module cannot have multiple default exports.
2825

2926
==== tests/cases/conformance/es6/modules/m2.ts (1 errors) ====
3027
import Entity from "./m1"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
tests/cases/conformance/externalModules/multipleExportDefault1.ts(1,25): error TS2528: A module cannot have multiple default exports.
2+
tests/cases/conformance/externalModules/multipleExportDefault1.ts(5,1): error TS2528: A module cannot have multiple default exports.
3+
4+
5+
==== tests/cases/conformance/externalModules/multipleExportDefault1.ts (2 errors) ====
6+
export default function Foo (){
7+
~~~
8+
!!! error TS2528: A module cannot have multiple default exports.
9+
10+
}
11+
12+
export default {
13+
~~~~~~~~~~~~~~~~
14+
uhoh: "another default",
15+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16+
};
17+
~~
18+
!!! error TS2528: A module cannot have multiple default exports.
19+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//// [multipleExportDefault1.ts]
2+
export default function Foo (){
3+
4+
}
5+
6+
export default {
7+
uhoh: "another default",
8+
};
9+
10+
11+
//// [multipleExportDefault1.js]
12+
"use strict";
13+
function Foo() {
14+
}
15+
exports.__esModule = true;
16+
exports["default"] = Foo;
17+
exports.__esModule = true;
18+
exports["default"] = {
19+
uhoh: "another default"
20+
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
tests/cases/conformance/externalModules/multipleExportDefault2.ts(1,1): error TS2528: A module cannot have multiple default exports.
2+
tests/cases/conformance/externalModules/multipleExportDefault2.ts(5,25): error TS2528: A module cannot have multiple default exports.
3+
4+
5+
==== tests/cases/conformance/externalModules/multipleExportDefault2.ts (2 errors) ====
6+
export default {
7+
~~~~~~~~~~~~~~~~
8+
uhoh: "another default",
9+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10+
};
11+
~~
12+
!!! error TS2528: A module cannot have multiple default exports.
13+
14+
export default function Foo() { }
15+
~~~
16+
!!! error TS2528: A module cannot have multiple default exports.
17+
18+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//// [multipleExportDefault2.ts]
2+
export default {
3+
uhoh: "another default",
4+
};
5+
6+
export default function Foo() { }
7+
8+
9+
10+
//// [multipleExportDefault2.js]
11+
"use strict";
12+
exports.__esModule = true;
13+
exports["default"] = {
14+
uhoh: "another default"
15+
};
16+
function Foo() { }
17+
exports.__esModule = true;
18+
exports["default"] = Foo;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
tests/cases/conformance/externalModules/multipleExportDefault3.ts(1,1): error TS2528: A module cannot have multiple default exports.
2+
tests/cases/conformance/externalModules/multipleExportDefault3.ts(5,22): error TS2528: A module cannot have multiple default exports.
3+
4+
5+
==== tests/cases/conformance/externalModules/multipleExportDefault3.ts (2 errors) ====
6+
export default {
7+
~~~~~~~~~~~~~~~~
8+
uhoh: "another default",
9+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10+
};
11+
~~
12+
!!! error TS2528: A module cannot have multiple default exports.
13+
14+
export default class C { }
15+
~
16+
!!! error TS2528: A module cannot have multiple default exports.
17+
18+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [multipleExportDefault3.ts]
2+
export default {
3+
uhoh: "another default",
4+
};
5+
6+
export default class C { }
7+
8+
9+
10+
//// [multipleExportDefault3.js]
11+
"use strict";
12+
exports.__esModule = true;
13+
exports["default"] = {
14+
uhoh: "another default"
15+
};
16+
var C = (function () {
17+
function C() {
18+
}
19+
return C;
20+
}());
21+
exports.__esModule = true;
22+
exports["default"] = C;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
tests/cases/conformance/externalModules/multipleExportDefault4.ts(1,22): error TS2528: A module cannot have multiple default exports.
2+
tests/cases/conformance/externalModules/multipleExportDefault4.ts(3,1): error TS2528: A module cannot have multiple default exports.
3+
4+
5+
==== tests/cases/conformance/externalModules/multipleExportDefault4.ts (2 errors) ====
6+
export default class C { }
7+
~
8+
!!! error TS2528: A module cannot have multiple default exports.
9+
10+
export default {
11+
~~~~~~~~~~~~~~~~
12+
uhoh: "another default",
13+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
14+
};
15+
~~
16+
!!! error TS2528: A module cannot have multiple default exports.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//// [multipleExportDefault4.ts]
2+
export default class C { }
3+
4+
export default {
5+
uhoh: "another default",
6+
};
7+
8+
//// [multipleExportDefault4.js]
9+
"use strict";
10+
var C = (function () {
11+
function C() {
12+
}
13+
return C;
14+
}());
15+
exports.__esModule = true;
16+
exports["default"] = C;
17+
exports.__esModule = true;
18+
exports["default"] = {
19+
uhoh: "another default"
20+
};
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
tests/cases/conformance/externalModules/multipleExportDefault5.ts(1,25): error TS2528: A module cannot have multiple default exports.
2+
tests/cases/conformance/externalModules/multipleExportDefault5.ts(2,22): error TS2528: A module cannot have multiple default exports.
3+
4+
5+
==== tests/cases/conformance/externalModules/multipleExportDefault5.ts (2 errors) ====
6+
export default function bar() { }
7+
~~~
8+
!!! error TS2528: A module cannot have multiple default exports.
9+
export default class C {}
10+
~
11+
!!! error TS2528: A module cannot have multiple default exports.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//// [multipleExportDefault5.ts]
2+
export default function bar() { }
3+
export default class C {}
4+
5+
//// [multipleExportDefault5.js]
6+
"use strict";
7+
function bar() { }
8+
exports.__esModule = true;
9+
exports["default"] = bar;
10+
var C = (function () {
11+
function C() {
12+
}
13+
return C;
14+
}());
15+
exports.__esModule = true;
16+
exports["default"] = C;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
tests/cases/conformance/externalModules/multipleExportDefault6.ts(1,1): error TS2528: A module cannot have multiple default exports.
2+
tests/cases/conformance/externalModules/multipleExportDefault6.ts(5,1): error TS2528: A module cannot have multiple default exports.
3+
4+
5+
==== tests/cases/conformance/externalModules/multipleExportDefault6.ts (2 errors) ====
6+
export default {
7+
~~~~~~~~~~~~~~~~
8+
lol: 1
9+
~~~~~~~~~~
10+
}
11+
~
12+
!!! error TS2528: A module cannot have multiple default exports.
13+
14+
export default {
15+
~~~~~~~~~~~~~~~~
16+
lol: 2
17+
~~~~~~~~~~
18+
}
19+
~
20+
!!! error TS2528: A module cannot have multiple default exports.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//// [multipleExportDefault6.ts]
2+
export default {
3+
lol: 1
4+
}
5+
6+
export default {
7+
lol: 2
8+
}
9+
10+
//// [multipleExportDefault6.js]
11+
"use strict";
12+
exports.__esModule = true;
13+
exports["default"] = {
14+
lol: 1
15+
};
16+
exports.__esModule = true;
17+
exports["default"] = {
18+
lol: 2
19+
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function Foo (){
2+
3+
}
4+
5+
export default {
6+
uhoh: "another default",
7+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default {
2+
uhoh: "another default",
3+
};
4+
5+
export default function Foo() { }
6+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default {
2+
uhoh: "another default",
3+
};
4+
5+
export default class C { }
6+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default class C { }
2+
3+
export default {
4+
uhoh: "another default",
5+
};
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export default function bar() { }
2+
export default class C {}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default {
2+
lol: 1
3+
}
4+
5+
export default {
6+
lol: 2
7+
}

0 commit comments

Comments
 (0)