Skip to content

Commit ab61bf2

Browse files
committed
Merge pull request #3532 from Microsoft/exportSpecifierScoping
Make resolveName ignore export specifiers without calling getSymbol
2 parents 27cccdd + 41e3973 commit ab61bf2

22 files changed

+303
-8
lines changed

src/compiler/checker.ts

+25-8
Original file line numberDiff line numberDiff line change
@@ -344,21 +344,38 @@ module ts {
344344
case SyntaxKind.SourceFile:
345345
if (!isExternalModule(<SourceFile>location)) break;
346346
case SyntaxKind.ModuleDeclaration:
347-
if (result = getSymbol(getSymbolOfNode(location).exports, name, meaning & SymbolFlags.ModuleMember)) {
348-
if (result.flags & meaning || !(result.flags & SymbolFlags.Alias && getDeclarationOfAliasSymbol(result).kind === SyntaxKind.ExportSpecifier)) {
349-
break loop;
350-
}
351-
result = undefined;
352-
}
353-
else if (location.kind === SyntaxKind.SourceFile ||
347+
let moduleExports = getSymbolOfNode(location).exports;
348+
if (location.kind === SyntaxKind.SourceFile ||
354349
(location.kind === SyntaxKind.ModuleDeclaration && (<ModuleDeclaration>location).name.kind === SyntaxKind.StringLiteral)) {
355-
result = getSymbolOfNode(location).exports["default"];
350+
351+
// It's an external module. Because of module/namespace merging, a module's exports are in scope,
352+
// yet we never want to treat an export specifier as putting a member in scope. Therefore,
353+
// if the name we find is purely an export specifier, it is not actually considered in scope.
354+
// Two things to note about this:
355+
// 1. We have to check this without calling getSymbol. The problem with calling getSymbol
356+
// on an export specifier is that it might find the export specifier itself, and try to
357+
// resolve it as an alias. This will cause the checker to consider the export specifier
358+
// a circular alias reference when it might not be.
359+
// 2. We check === SymbolFlags.Alias in order to check that the symbol is *purely*
360+
// an alias. If we used &, we'd be throwing out symbols that have non alias aspects,
361+
// which is not the desired behavior.
362+
if (hasProperty(moduleExports, name) &&
363+
moduleExports[name].flags === SymbolFlags.Alias &&
364+
getDeclarationOfKind(moduleExports[name], SyntaxKind.ExportSpecifier)) {
365+
break;
366+
}
367+
368+
result = moduleExports["default"];
356369
let localSymbol = getLocalSymbolForExportDefault(result);
357370
if (result && localSymbol && (result.flags & meaning) && localSymbol.name === name) {
358371
break loop;
359372
}
360373
result = undefined;
361374
}
375+
376+
if (result = getSymbol(moduleExports, name, meaning & SymbolFlags.ModuleMember)) {
377+
break loop;
378+
}
362379
break;
363380
case SyntaxKind.EnumDeclaration:
364381
if (result = getSymbol(getSymbolOfNode(location).exports, name, meaning & SymbolFlags.EnumMember)) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//// [exportSpecifierAndExportedMemberDeclaration.ts]
2+
declare module "m2" {
3+
export module X {
4+
interface I { }
5+
}
6+
function Y();
7+
export { Y as X };
8+
function Z(): X.I;
9+
}
10+
11+
declare module "m2" {
12+
function Z2(): X.I;
13+
}
14+
15+
//// [exportSpecifierAndExportedMemberDeclaration.js]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
=== tests/cases/compiler/exportSpecifierAndExportedMemberDeclaration.ts ===
2+
declare module "m2" {
3+
export module X {
4+
>X : Symbol(X, Decl(exportSpecifierAndExportedMemberDeclaration.ts, 0, 21), Decl(exportSpecifierAndExportedMemberDeclaration.ts, 5, 12))
5+
6+
interface I { }
7+
>I : Symbol(I, Decl(exportSpecifierAndExportedMemberDeclaration.ts, 1, 21))
8+
}
9+
function Y();
10+
>Y : Symbol(Y, Decl(exportSpecifierAndExportedMemberDeclaration.ts, 3, 5))
11+
12+
export { Y as X };
13+
>Y : Symbol(X, Decl(exportSpecifierAndExportedMemberDeclaration.ts, 0, 21), Decl(exportSpecifierAndExportedMemberDeclaration.ts, 5, 12))
14+
>X : Symbol(X, Decl(exportSpecifierAndExportedMemberDeclaration.ts, 0, 21), Decl(exportSpecifierAndExportedMemberDeclaration.ts, 5, 12))
15+
16+
function Z(): X.I;
17+
>Z : Symbol(Z, Decl(exportSpecifierAndExportedMemberDeclaration.ts, 5, 22))
18+
>X : Symbol(X, Decl(exportSpecifierAndExportedMemberDeclaration.ts, 0, 21), Decl(exportSpecifierAndExportedMemberDeclaration.ts, 5, 12))
19+
>I : Symbol(X.I, Decl(exportSpecifierAndExportedMemberDeclaration.ts, 1, 21))
20+
}
21+
22+
declare module "m2" {
23+
function Z2(): X.I;
24+
>Z2 : Symbol(Z2, Decl(exportSpecifierAndExportedMemberDeclaration.ts, 9, 21))
25+
>X : Symbol(X, Decl(exportSpecifierAndExportedMemberDeclaration.ts, 0, 21), Decl(exportSpecifierAndExportedMemberDeclaration.ts, 5, 12))
26+
>I : Symbol(X.I, Decl(exportSpecifierAndExportedMemberDeclaration.ts, 1, 21))
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
=== tests/cases/compiler/exportSpecifierAndExportedMemberDeclaration.ts ===
2+
declare module "m2" {
3+
export module X {
4+
>X : () => any
5+
6+
interface I { }
7+
>I : I
8+
}
9+
function Y();
10+
>Y : () => any
11+
12+
export { Y as X };
13+
>Y : () => any
14+
>X : () => any
15+
16+
function Z(): X.I;
17+
>Z : () => X.I
18+
>X : any
19+
>I : X.I
20+
}
21+
22+
declare module "m2" {
23+
function Z2(): X.I;
24+
>Z2 : () => X.I
25+
>X : any
26+
>I : X.I
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
tests/cases/compiler/exportSpecifierAndLocalMemberDeclaration.ts(11,20): error TS2503: Cannot find namespace 'X'.
2+
3+
4+
==== tests/cases/compiler/exportSpecifierAndLocalMemberDeclaration.ts (1 errors) ====
5+
declare module "m2" {
6+
module X {
7+
interface I { }
8+
}
9+
function Y();
10+
export { Y as X };
11+
function Z(): X.I;
12+
}
13+
14+
declare module "m2" {
15+
function Z2(): X.I;
16+
~
17+
!!! error TS2503: Cannot find namespace 'X'.
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//// [exportSpecifierAndLocalMemberDeclaration.ts]
2+
declare module "m2" {
3+
module X {
4+
interface I { }
5+
}
6+
function Y();
7+
export { Y as X };
8+
function Z(): X.I;
9+
}
10+
11+
declare module "m2" {
12+
function Z2(): X.I;
13+
}
14+
15+
//// [exportSpecifierAndLocalMemberDeclaration.js]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//// [exportSpecifierReferencingOuterDeclaration1.ts]
2+
declare module X { export interface bar { } }
3+
declare module "m" {
4+
export { X };
5+
export function foo(): X.bar;
6+
}
7+
8+
//// [exportSpecifierReferencingOuterDeclaration1.js]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
=== tests/cases/compiler/exportSpecifierReferencingOuterDeclaration1.ts ===
2+
declare module X { export interface bar { } }
3+
>X : Symbol(X, Decl(exportSpecifierReferencingOuterDeclaration1.ts, 0, 0))
4+
>bar : Symbol(bar, Decl(exportSpecifierReferencingOuterDeclaration1.ts, 0, 18))
5+
6+
declare module "m" {
7+
export { X };
8+
>X : Symbol(X, Decl(exportSpecifierReferencingOuterDeclaration1.ts, 2, 12))
9+
10+
export function foo(): X.bar;
11+
>foo : Symbol(foo, Decl(exportSpecifierReferencingOuterDeclaration1.ts, 2, 17))
12+
>X : Symbol(X, Decl(exportSpecifierReferencingOuterDeclaration1.ts, 0, 0))
13+
>bar : Symbol(X.bar, Decl(exportSpecifierReferencingOuterDeclaration1.ts, 0, 18))
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
=== tests/cases/compiler/exportSpecifierReferencingOuterDeclaration1.ts ===
2+
declare module X { export interface bar { } }
3+
>X : any
4+
>bar : bar
5+
6+
declare module "m" {
7+
export { X };
8+
>X : any
9+
10+
export function foo(): X.bar;
11+
>foo : () => X.bar
12+
>X : any
13+
>bar : X.bar
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//// [tests/cases/compiler/exportSpecifierReferencingOuterDeclaration2.ts] ////
2+
3+
//// [exportSpecifierReferencingOuterDeclaration2_A.ts]
4+
declare module X { export interface bar { } }
5+
6+
//// [exportSpecifierReferencingOuterDeclaration2_B.ts]
7+
export { X };
8+
export declare function foo(): X.bar;
9+
10+
//// [exportSpecifierReferencingOuterDeclaration2_A.js]
11+
//// [exportSpecifierReferencingOuterDeclaration2_B.js]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
=== tests/cases/compiler/exportSpecifierReferencingOuterDeclaration2_A.ts ===
2+
declare module X { export interface bar { } }
3+
>X : Symbol(X, Decl(exportSpecifierReferencingOuterDeclaration2_A.ts, 0, 0))
4+
>bar : Symbol(bar, Decl(exportSpecifierReferencingOuterDeclaration2_A.ts, 0, 18))
5+
6+
=== tests/cases/compiler/exportSpecifierReferencingOuterDeclaration2_B.ts ===
7+
export { X };
8+
>X : Symbol(X, Decl(exportSpecifierReferencingOuterDeclaration2_B.ts, 0, 8))
9+
10+
export declare function foo(): X.bar;
11+
>foo : Symbol(foo, Decl(exportSpecifierReferencingOuterDeclaration2_B.ts, 0, 13))
12+
>X : Symbol(X, Decl(exportSpecifierReferencingOuterDeclaration2_A.ts, 0, 0))
13+
>bar : Symbol(X.bar, Decl(exportSpecifierReferencingOuterDeclaration2_A.ts, 0, 18))
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
=== tests/cases/compiler/exportSpecifierReferencingOuterDeclaration2_A.ts ===
2+
declare module X { export interface bar { } }
3+
>X : any
4+
>bar : bar
5+
6+
=== tests/cases/compiler/exportSpecifierReferencingOuterDeclaration2_B.ts ===
7+
export { X };
8+
>X : any
9+
10+
export declare function foo(): X.bar;
11+
>foo : () => X.bar
12+
>X : any
13+
>bar : X.bar
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
tests/cases/compiler/exportSpecifierReferencingOuterDeclaration3.ts(6,30): error TS2305: Module 'X' has no exported member 'bar'.
2+
3+
4+
==== tests/cases/compiler/exportSpecifierReferencingOuterDeclaration3.ts (1 errors) ====
5+
declare module X { export interface bar { } }
6+
declare module "m" {
7+
module X { export interface foo { } }
8+
export { X };
9+
export function foo(): X.foo;
10+
export function bar(): X.bar; // error
11+
~~~
12+
!!! error TS2305: Module 'X' has no exported member 'bar'.
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//// [exportSpecifierReferencingOuterDeclaration3.ts]
2+
declare module X { export interface bar { } }
3+
declare module "m" {
4+
module X { export interface foo { } }
5+
export { X };
6+
export function foo(): X.foo;
7+
export function bar(): X.bar; // error
8+
}
9+
10+
//// [exportSpecifierReferencingOuterDeclaration3.js]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
tests/cases/compiler/exportSpecifierReferencingOuterDeclaration2_B.ts(4,34): error TS2305: Module 'X' has no exported member 'bar'.
2+
3+
4+
==== tests/cases/compiler/exportSpecifierReferencingOuterDeclaration2_A.ts (0 errors) ====
5+
declare module X { export interface bar { } }
6+
7+
==== tests/cases/compiler/exportSpecifierReferencingOuterDeclaration2_B.ts (1 errors) ====
8+
declare module X { export interface foo { } }
9+
export { X };
10+
export declare function foo(): X.foo;
11+
export declare function bar(): X.bar; // error
12+
~~~
13+
!!! error TS2305: Module 'X' has no exported member 'bar'.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//// [tests/cases/compiler/exportSpecifierReferencingOuterDeclaration4.ts] ////
2+
3+
//// [exportSpecifierReferencingOuterDeclaration2_A.ts]
4+
declare module X { export interface bar { } }
5+
6+
//// [exportSpecifierReferencingOuterDeclaration2_B.ts]
7+
declare module X { export interface foo { } }
8+
export { X };
9+
export declare function foo(): X.foo;
10+
export declare function bar(): X.bar; // error
11+
12+
//// [exportSpecifierReferencingOuterDeclaration2_A.js]
13+
//// [exportSpecifierReferencingOuterDeclaration2_B.js]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
declare module "m2" {
2+
export module X {
3+
interface I { }
4+
}
5+
function Y();
6+
export { Y as X };
7+
function Z(): X.I;
8+
}
9+
10+
declare module "m2" {
11+
function Z2(): X.I;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
declare module "m2" {
2+
module X {
3+
interface I { }
4+
}
5+
function Y();
6+
export { Y as X };
7+
function Z(): X.I;
8+
}
9+
10+
declare module "m2" {
11+
function Z2(): X.I;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
declare module X { export interface bar { } }
2+
declare module "m" {
3+
export { X };
4+
export function foo(): X.bar;
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// @module: commonjs
2+
// @Filename: exportSpecifierReferencingOuterDeclaration2_A.ts
3+
declare module X { export interface bar { } }
4+
5+
// @Filename: exportSpecifierReferencingOuterDeclaration2_B.ts
6+
export { X };
7+
export declare function foo(): X.bar;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
declare module X { export interface bar { } }
2+
declare module "m" {
3+
module X { export interface foo { } }
4+
export { X };
5+
export function foo(): X.foo;
6+
export function bar(): X.bar; // error
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// @module: commonjs
2+
// @Filename: exportSpecifierReferencingOuterDeclaration2_A.ts
3+
declare module X { export interface bar { } }
4+
5+
// @Filename: exportSpecifierReferencingOuterDeclaration2_B.ts
6+
declare module X { export interface foo { } }
7+
export { X };
8+
export declare function foo(): X.foo;
9+
export declare function bar(): X.bar; // error

0 commit comments

Comments
 (0)