Skip to content

Commit cf5c284

Browse files
committed
Add tests for loosened isolatedModules script checks
1 parent c1de572 commit cf5c284

6 files changed

+311
-21
lines changed

src/compiler/checker.ts

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -42312,30 +42312,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4231242312
// The following checks only apply on a non-ambient instantiated module declaration.
4231342313
if (symbol.flags & SymbolFlags.ValueModule
4231442314
&& !inAmbientContext
42315-
&& symbol.declarations
42316-
&& symbol.declarations.length > 1
42317-
&& isInstantiatedModule(node, shouldPreserveConstEnums(compilerOptions))) {
42318-
const firstNonAmbientClassOrFunc = getFirstNonAmbientClassOrFunctionDeclaration(symbol);
42319-
if (firstNonAmbientClassOrFunc) {
42320-
if (getSourceFileOfNode(node) !== getSourceFileOfNode(firstNonAmbientClassOrFunc)) {
42321-
error(node.name, Diagnostics.A_namespace_declaration_cannot_be_in_a_different_file_from_a_class_or_function_with_which_it_is_merged);
42322-
}
42323-
else if (node.pos < firstNonAmbientClassOrFunc.pos) {
42324-
error(node.name, Diagnostics.A_namespace_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged);
42325-
}
42326-
}
42327-
42328-
// if the module merges with a class declaration in the same lexical scope,
42329-
// we need to track this to ensure the correct emit.
42330-
const mergedClass = getDeclarationOfKind(symbol, SyntaxKind.ClassDeclaration);
42331-
if (mergedClass &&
42332-
inSameLexicalScope(node, mergedClass)) {
42333-
getNodeLinks(node).flags |= NodeCheckFlags.LexicalModuleMergesWithClass;
42334-
}
42335-
42315+
&& isInstantiatedModule(node, shouldPreserveConstEnums(compilerOptions))
42316+
) {
4233642317
if (getIsolatedModules(compilerOptions) && !getSourceFileOfNode(node).externalModuleIndicator) {
42318+
// This could be loosened a little if needed. The only problem we are trying to avoid is unqualified
42319+
// references to namespace members declared in other files. But use of namespaces is discouraged anyway,
42320+
// so for now we will just not allow them in scripts, which is the only place they can merge cross-file.
4233742321
error(node.name, Diagnostics.Namespaces_are_not_allowed_in_global_script_files_when_0_is_enabled_If_this_file_is_not_intended_to_be_a_global_script_set_moduleDetection_to_force_or_add_an_empty_export_statement, isolatedModulesLikeFlagName);
4233842322
}
42323+
if (symbol.declarations?.length > 1) {
42324+
const firstNonAmbientClassOrFunc = getFirstNonAmbientClassOrFunctionDeclaration(symbol);
42325+
if (firstNonAmbientClassOrFunc) {
42326+
if (getSourceFileOfNode(node) !== getSourceFileOfNode(firstNonAmbientClassOrFunc)) {
42327+
error(node.name, Diagnostics.A_namespace_declaration_cannot_be_in_a_different_file_from_a_class_or_function_with_which_it_is_merged);
42328+
}
42329+
else if (node.pos < firstNonAmbientClassOrFunc.pos) {
42330+
error(node.name, Diagnostics.A_namespace_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged);
42331+
}
42332+
}
42333+
42334+
// if the module merges with a class declaration in the same lexical scope,
42335+
// we need to track this to ensure the correct emit.
42336+
const mergedClass = getDeclarationOfKind(symbol, SyntaxKind.ClassDeclaration);
42337+
if (mergedClass &&
42338+
inSameLexicalScope(node, mergedClass)) {
42339+
getNodeLinks(node).flags |= NodeCheckFlags.LexicalModuleMergesWithClass;
42340+
}
42341+
}
4233942342
}
4234042343

4234142344
if (isAmbientExternalModule) {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
tests/cases/compiler/enum2.ts(3,9): error TS1278: Cannot access 'A' from another file without qualification when 'isolatedModules' is enabled. Use 'Enum.A' instead.
2+
tests/cases/compiler/enum2.ts(4,9): error TS1278: Cannot access 'X' from another file without qualification when 'isolatedModules' is enabled. Use 'Enum.X' instead.
3+
tests/cases/compiler/script-namespaces.ts(1,11): error TS1277: Namespaces are not allowed in global script files when 'isolatedModules' is enabled. If this file is not intended to be a global script, set 'moduleDetection' to 'force' or add an empty 'export {}' statement.
4+
5+
6+
==== tests/cases/compiler/script-namespaces.ts (1 errors) ====
7+
namespace Instantiated {
8+
~~~~~~~~~~~~
9+
!!! error TS1277: Namespaces are not allowed in global script files when 'isolatedModules' is enabled. If this file is not intended to be a global script, set 'moduleDetection' to 'force' or add an empty 'export {}' statement.
10+
export const x = 1;
11+
}
12+
namespace Uninstantiated {
13+
export type T = number;
14+
}
15+
declare namespace Ambient {
16+
export const x: number;
17+
}
18+
19+
==== tests/cases/compiler/module-namespaces.ts (0 errors) ====
20+
export namespace Instantiated {
21+
export const x = 1;
22+
}
23+
24+
==== tests/cases/compiler/enum1.ts (0 errors) ====
25+
enum Enum { A, B, C }
26+
declare enum Enum { X = 1_000_000 }
27+
const d = 'd';
28+
29+
==== tests/cases/compiler/enum2.ts (2 errors) ====
30+
enum Enum {
31+
D = d,
32+
E = A, // error
33+
~
34+
!!! error TS1278: Cannot access 'A' from another file without qualification when 'isolatedModules' is enabled. Use 'Enum.A' instead.
35+
Y = X, // error
36+
~
37+
!!! error TS1278: Cannot access 'X' from another file without qualification when 'isolatedModules' is enabled. Use 'Enum.X' instead.
38+
Z = Enum.A
39+
}
40+
41+
declare enum Enum {
42+
F = A
43+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//// [tests/cases/compiler/isolatedModulesGlobalNamespacesAndEnums.ts] ////
2+
3+
//// [script-namespaces.ts]
4+
namespace Instantiated {
5+
export const x = 1;
6+
}
7+
namespace Uninstantiated {
8+
export type T = number;
9+
}
10+
declare namespace Ambient {
11+
export const x: number;
12+
}
13+
14+
//// [module-namespaces.ts]
15+
export namespace Instantiated {
16+
export const x = 1;
17+
}
18+
19+
//// [enum1.ts]
20+
enum Enum { A, B, C }
21+
declare enum Enum { X = 1_000_000 }
22+
const d = 'd';
23+
24+
//// [enum2.ts]
25+
enum Enum {
26+
D = d,
27+
E = A, // error
28+
Y = X, // error
29+
Z = Enum.A
30+
}
31+
32+
declare enum Enum {
33+
F = A
34+
}
35+
36+
//// [script-namespaces.js]
37+
var Instantiated;
38+
(function (Instantiated) {
39+
Instantiated.x = 1;
40+
})(Instantiated || (Instantiated = {}));
41+
//// [module-namespaces.js]
42+
"use strict";
43+
exports.__esModule = true;
44+
exports.Instantiated = void 0;
45+
var Instantiated;
46+
(function (Instantiated) {
47+
Instantiated.x = 1;
48+
})(Instantiated = exports.Instantiated || (exports.Instantiated = {}));
49+
//// [enum1.js]
50+
var Enum;
51+
(function (Enum) {
52+
Enum[Enum["A"] = 0] = "A";
53+
Enum[Enum["B"] = 1] = "B";
54+
Enum[Enum["C"] = 2] = "C";
55+
})(Enum || (Enum = {}));
56+
var d = 'd';
57+
//// [enum2.js]
58+
var Enum;
59+
(function (Enum) {
60+
Enum["D"] = "d";
61+
Enum[Enum["E"] = 0] = "E";
62+
Enum[Enum["Y"] = 1000000] = "Y";
63+
Enum[Enum["Z"] = 0] = "Z";
64+
})(Enum || (Enum = {}));
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
=== tests/cases/compiler/script-namespaces.ts ===
2+
namespace Instantiated {
3+
>Instantiated : Symbol(Instantiated, Decl(script-namespaces.ts, 0, 0))
4+
5+
export const x = 1;
6+
>x : Symbol(x, Decl(script-namespaces.ts, 1, 16))
7+
}
8+
namespace Uninstantiated {
9+
>Uninstantiated : Symbol(Uninstantiated, Decl(script-namespaces.ts, 2, 1))
10+
11+
export type T = number;
12+
>T : Symbol(T, Decl(script-namespaces.ts, 3, 26))
13+
}
14+
declare namespace Ambient {
15+
>Ambient : Symbol(Ambient, Decl(script-namespaces.ts, 5, 1))
16+
17+
export const x: number;
18+
>x : Symbol(x, Decl(script-namespaces.ts, 7, 16))
19+
}
20+
21+
=== tests/cases/compiler/module-namespaces.ts ===
22+
export namespace Instantiated {
23+
>Instantiated : Symbol(Instantiated, Decl(module-namespaces.ts, 0, 0))
24+
25+
export const x = 1;
26+
>x : Symbol(x, Decl(module-namespaces.ts, 1, 16))
27+
}
28+
29+
=== tests/cases/compiler/enum1.ts ===
30+
enum Enum { A, B, C }
31+
>Enum : Symbol(Enum, Decl(enum1.ts, 0, 0), Decl(enum1.ts, 0, 21), Decl(enum2.ts, 0, 0), Decl(enum2.ts, 5, 1))
32+
>A : Symbol(Enum.A, Decl(enum1.ts, 0, 11))
33+
>B : Symbol(Enum.B, Decl(enum1.ts, 0, 14))
34+
>C : Symbol(Enum.C, Decl(enum1.ts, 0, 17))
35+
36+
declare enum Enum { X = 1_000_000 }
37+
>Enum : Symbol(Enum, Decl(enum1.ts, 0, 0), Decl(enum1.ts, 0, 21), Decl(enum2.ts, 0, 0), Decl(enum2.ts, 5, 1))
38+
>X : Symbol(Enum.X, Decl(enum1.ts, 1, 19))
39+
40+
const d = 'd';
41+
>d : Symbol(d, Decl(enum1.ts, 2, 5))
42+
43+
=== tests/cases/compiler/enum2.ts ===
44+
enum Enum {
45+
>Enum : Symbol(Enum, Decl(enum1.ts, 0, 0), Decl(enum1.ts, 0, 21), Decl(enum2.ts, 0, 0), Decl(enum2.ts, 5, 1))
46+
47+
D = d,
48+
>D : Symbol(Enum.D, Decl(enum2.ts, 0, 11))
49+
>d : Symbol(d, Decl(enum1.ts, 2, 5))
50+
51+
E = A, // error
52+
>E : Symbol(Enum.E, Decl(enum2.ts, 1, 10))
53+
>A : Symbol(Enum.A, Decl(enum1.ts, 0, 11))
54+
55+
Y = X, // error
56+
>Y : Symbol(Enum.Y, Decl(enum2.ts, 2, 10))
57+
>X : Symbol(Enum.X, Decl(enum1.ts, 1, 19))
58+
59+
Z = Enum.A
60+
>Z : Symbol(Enum.Z, Decl(enum2.ts, 3, 10))
61+
>Enum.A : Symbol(Enum.A, Decl(enum1.ts, 0, 11))
62+
>Enum : Symbol(Enum, Decl(enum1.ts, 0, 0), Decl(enum1.ts, 0, 21), Decl(enum2.ts, 0, 0), Decl(enum2.ts, 5, 1))
63+
>A : Symbol(Enum.A, Decl(enum1.ts, 0, 11))
64+
}
65+
66+
declare enum Enum {
67+
>Enum : Symbol(Enum, Decl(enum1.ts, 0, 0), Decl(enum1.ts, 0, 21), Decl(enum2.ts, 0, 0), Decl(enum2.ts, 5, 1))
68+
69+
F = A
70+
>F : Symbol(Enum.F, Decl(enum2.ts, 7, 19))
71+
>A : Symbol(Enum.A, Decl(enum1.ts, 0, 11))
72+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
=== tests/cases/compiler/script-namespaces.ts ===
2+
namespace Instantiated {
3+
>Instantiated : typeof Instantiated
4+
5+
export const x = 1;
6+
>x : 1
7+
>1 : 1
8+
}
9+
namespace Uninstantiated {
10+
export type T = number;
11+
>T : number
12+
}
13+
declare namespace Ambient {
14+
>Ambient : typeof Ambient
15+
16+
export const x: number;
17+
>x : number
18+
}
19+
20+
=== tests/cases/compiler/module-namespaces.ts ===
21+
export namespace Instantiated {
22+
>Instantiated : typeof Instantiated
23+
24+
export const x = 1;
25+
>x : 1
26+
>1 : 1
27+
}
28+
29+
=== tests/cases/compiler/enum1.ts ===
30+
enum Enum { A, B, C }
31+
>Enum : Enum
32+
>A : Enum.A
33+
>B : Enum.B
34+
>C : Enum.C
35+
36+
declare enum Enum { X = 1_000_000 }
37+
>Enum : Enum
38+
>X : Enum.X
39+
>1_000_000 : 1000000
40+
41+
const d = 'd';
42+
>d : "d"
43+
>'d' : "d"
44+
45+
=== tests/cases/compiler/enum2.ts ===
46+
enum Enum {
47+
>Enum : Enum
48+
49+
D = d,
50+
>D : Enum.D
51+
>d : "d"
52+
53+
E = A, // error
54+
>E : Enum.A
55+
>A : Enum.A
56+
57+
Y = X, // error
58+
>Y : Enum.X
59+
>X : Enum.X
60+
61+
Z = Enum.A
62+
>Z : Enum.A
63+
>Enum.A : Enum.A
64+
>Enum : typeof Enum
65+
>A : Enum.A
66+
}
67+
68+
declare enum Enum {
69+
>Enum : Enum
70+
71+
F = A
72+
>F : Enum.A
73+
>A : Enum.A
74+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// @isolatedModules: true
2+
3+
// @Filename: script-namespaces.ts
4+
namespace Instantiated {
5+
export const x = 1;
6+
}
7+
namespace Uninstantiated {
8+
export type T = number;
9+
}
10+
declare namespace Ambient {
11+
export const x: number;
12+
}
13+
14+
// @Filename: module-namespaces.ts
15+
export namespace Instantiated {
16+
export const x = 1;
17+
}
18+
19+
// @Filename: enum1.ts
20+
enum Enum { A, B, C }
21+
declare enum Enum { X = 1_000_000 }
22+
const d = 'd';
23+
24+
// @Filename: enum2.ts
25+
enum Enum {
26+
D = d,
27+
E = A, // error
28+
Y = X, // error
29+
Z = Enum.A
30+
}
31+
32+
declare enum Enum {
33+
F = A
34+
}

0 commit comments

Comments
 (0)