Skip to content

Commit a5607a4

Browse files
authored
Dont allow namespace reexport symbols when looking up valid local names (microsoft#43969)
1 parent 233f28c commit a5607a4

File tree

32 files changed

+110
-34
lines changed

32 files changed

+110
-34
lines changed

src/compiler/checker.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3935,12 +3935,12 @@ namespace ts {
39353935
return typeCopy;
39363936
}
39373937

3938-
function forEachSymbolTableInScope<T>(enclosingDeclaration: Node | undefined, callback: (symbolTable: SymbolTable) => T): T {
3938+
function forEachSymbolTableInScope<T>(enclosingDeclaration: Node | undefined, callback: (symbolTable: SymbolTable, ignoreQualification?: boolean, isLocalNameLookup?: boolean) => T): T {
39393939
let result: T;
39403940
for (let location = enclosingDeclaration; location; location = location.parent) {
39413941
// Locals of a source file are not in scope (because they get merged into the global symbol table)
39423942
if (location.locals && !isGlobalSourceFile(location)) {
3943-
if (result = callback(location.locals)) {
3943+
if (result = callback(location.locals, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true)) {
39443944
return result;
39453945
}
39463946
}
@@ -3955,7 +3955,7 @@ namespace ts {
39553955
// `sym` may not have exports if this module declaration is backed by the symbol for a `const` that's being rewritten
39563956
// into a namespace - in such cases, it's best to just let the namespace appear empty (the const members couldn't have referred
39573957
// to one another anyway)
3958-
if (result = callback(sym?.exports || emptySymbols)) {
3958+
if (result = callback(sym?.exports || emptySymbols, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true)) {
39593959
return result;
39603960
}
39613961
break;
@@ -3983,7 +3983,7 @@ namespace ts {
39833983
}
39843984
}
39853985

3986-
return callback(globals);
3986+
return callback(globals, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true);
39873987
}
39883988

39893989
function getQualifiedLeftMeaning(rightMeaning: SymbolFlags) {
@@ -4006,12 +4006,12 @@ namespace ts {
40064006
/**
40074007
* @param {ignoreQualification} boolean Set when a symbol is being looked for through the exports of another symbol (meaning we have a route to qualify it already)
40084008
*/
4009-
function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable, ignoreQualification?: boolean): Symbol[] | undefined {
4009+
function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable, ignoreQualification?: boolean, isLocalNameLookup?: boolean): Symbol[] | undefined {
40104010
if (!pushIfUnique(visitedSymbolTables!, symbols)) {
40114011
return undefined;
40124012
}
40134013

4014-
const result = trySymbolTable(symbols, ignoreQualification);
4014+
const result = trySymbolTable(symbols, ignoreQualification, isLocalNameLookup);
40154015
visitedSymbolTables!.pop();
40164016
return result;
40174017
}
@@ -4032,7 +4032,7 @@ namespace ts {
40324032
(ignoreQualification || canQualifySymbol(getMergedSymbol(symbolFromSymbolTable), meaning));
40334033
}
40344034

4035-
function trySymbolTable(symbols: SymbolTable, ignoreQualification: boolean | undefined): Symbol[] | undefined {
4035+
function trySymbolTable(symbols: SymbolTable, ignoreQualification: boolean | undefined, isLocalNameLookup: boolean | undefined): Symbol[] | undefined {
40364036
// If symbol is directly available by its name in the symbol table
40374037
if (isAccessible(symbols.get(symbol!.escapedName)!, /*resolvedAliasSymbol*/ undefined, ignoreQualification)) {
40384038
return [symbol!];
@@ -4046,6 +4046,8 @@ namespace ts {
40464046
&& !(isUMDExportSymbol(symbolFromSymbolTable) && enclosingDeclaration && isExternalModule(getSourceFileOfNode(enclosingDeclaration)))
40474047
// If `!useOnlyExternalAliasing`, we can use any type of alias to get the name
40484048
&& (!useOnlyExternalAliasing || some(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration))
4049+
// If we're looking up a local name to reference directly, omit namespace reexports, otherwise when we're trawling through an export list to make a dotted name, we can keep it
4050+
&& (isLocalNameLookup ? !some(symbolFromSymbolTable.declarations, isNamespaceReexportDeclaration) : true)
40494051
// While exports are generally considered to be in scope, export-specifier declared symbols are _not_
40504052
// See similar comment in `resolveName` for details
40514053
&& (ignoreQualification || !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier))
@@ -4160,7 +4162,7 @@ namespace ts {
41604162
return hasAccessibleDeclarations;
41614163
}
41624164
}
4163-
else if (allowModules) {
4165+
if (allowModules) {
41644166
if (some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) {
41654167
if (shouldComputeAliasesToMakeVisible) {
41664168
earlyModuleBail = true;

src/compiler/utilities.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1971,6 +1971,10 @@ namespace ts {
19711971
return node.kind === SyntaxKind.TypeQuery;
19721972
}
19731973

1974+
export function isNamespaceReexportDeclaration(node: Node): boolean {
1975+
return isNamespaceExport(node) && !!node.parent.moduleSpecifier;
1976+
}
1977+
19741978
export function isExternalModuleImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration & { moduleReference: ExternalModuleReference } {
19751979
return node.kind === SyntaxKind.ImportEqualsDeclaration && (<ImportEqualsDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference;
19761980
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//// [tests/cases/compiler/declarationEmitDoesNotUseReexportedNamespaceAsLocal.ts] ////
2+
3+
//// [sub.ts]
4+
export function a() {}
5+
//// [index.ts]
6+
export const x = add(import("./sub"));
7+
export * as Q from "./sub";
8+
declare function add<T>(x: Promise<T>): T;
9+
10+
//// [sub.js]
11+
export function a() { }
12+
//// [index.js]
13+
export const x = add(import("./sub"));
14+
export * as Q from "./sub";
15+
16+
17+
//// [sub.d.ts]
18+
export declare function a(): void;
19+
//// [index.d.ts]
20+
export declare const x: typeof import("./sub");
21+
export * as Q from "./sub";
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
=== tests/cases/compiler/sub.ts ===
2+
export function a() {}
3+
>a : Symbol(a, Decl(sub.ts, 0, 0))
4+
5+
=== tests/cases/compiler/index.ts ===
6+
export const x = add(import("./sub"));
7+
>x : Symbol(x, Decl(index.ts, 0, 12))
8+
>add : Symbol(add, Decl(index.ts, 1, 27))
9+
>"./sub" : Symbol("tests/cases/compiler/sub", Decl(sub.ts, 0, 0))
10+
11+
export * as Q from "./sub";
12+
>Q : Symbol(Q, Decl(index.ts, 1, 6))
13+
14+
declare function add<T>(x: Promise<T>): T;
15+
>add : Symbol(add, Decl(index.ts, 1, 27))
16+
>T : Symbol(T, Decl(index.ts, 2, 21))
17+
>x : Symbol(x, Decl(index.ts, 2, 24))
18+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --))
19+
>T : Symbol(T, Decl(index.ts, 2, 21))
20+
>T : Symbol(T, Decl(index.ts, 2, 21))
21+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
=== tests/cases/compiler/sub.ts ===
2+
export function a() {}
3+
>a : () => void
4+
5+
=== tests/cases/compiler/index.ts ===
6+
export const x = add(import("./sub"));
7+
>x : typeof import("tests/cases/compiler/sub")
8+
>add(import("./sub")) : typeof import("tests/cases/compiler/sub")
9+
>add : <T>(x: Promise<T>) => T
10+
>import("./sub") : Promise<typeof import("tests/cases/compiler/sub")>
11+
>"./sub" : "./sub"
12+
13+
export * as Q from "./sub";
14+
>Q : typeof import("tests/cases/compiler/sub")
15+
16+
declare function add<T>(x: Promise<T>): T;
17+
>add : <T>(x: Promise<T>) => T
18+
>x : Promise<T>
19+

tests/baselines/reference/exportAsNamespace1(module=amd).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const b = 2;
99

1010
=== tests/cases/conformance/es2020/modules/1.ts ===
1111
export * as ns from './0';
12-
>ns : typeof ns
12+
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
1313

1414
ns.a;
1515
>ns.a : any

tests/baselines/reference/exportAsNamespace1(module=commonjs).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const b = 2;
99

1010
=== tests/cases/conformance/es2020/modules/1.ts ===
1111
export * as ns from './0';
12-
>ns : typeof ns
12+
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
1313

1414
ns.a;
1515
>ns.a : any

tests/baselines/reference/exportAsNamespace1(module=es2015).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const b = 2;
99

1010
=== tests/cases/conformance/es2020/modules/1.ts ===
1111
export * as ns from './0';
12-
>ns : typeof ns
12+
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
1313

1414
ns.a;
1515
>ns.a : any

tests/baselines/reference/exportAsNamespace1(module=esnext).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const b = 2;
99

1010
=== tests/cases/conformance/es2020/modules/1.ts ===
1111
export * as ns from './0';
12-
>ns : typeof ns
12+
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
1313

1414
ns.a;
1515
>ns.a : any

tests/baselines/reference/exportAsNamespace1(module=system).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const b = 2;
99

1010
=== tests/cases/conformance/es2020/modules/1.ts ===
1111
export * as ns from './0';
12-
>ns : typeof ns
12+
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
1313

1414
ns.a;
1515
>ns.a : any

tests/baselines/reference/exportAsNamespace1(module=umd).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const b = 2;
99

1010
=== tests/cases/conformance/es2020/modules/1.ts ===
1111
export * as ns from './0';
12-
>ns : typeof ns
12+
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
1313

1414
ns.a;
1515
>ns.a : any

tests/baselines/reference/exportAsNamespace2(module=amd).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const b = 2;
99

1010
=== tests/cases/conformance/es2020/modules/1.ts ===
1111
export * as ns from './0';
12-
>ns : typeof ns
12+
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
1313

1414
ns.a;
1515
>ns.a : any

tests/baselines/reference/exportAsNamespace2(module=commonjs).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const b = 2;
99

1010
=== tests/cases/conformance/es2020/modules/1.ts ===
1111
export * as ns from './0';
12-
>ns : typeof ns
12+
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
1313

1414
ns.a;
1515
>ns.a : any

tests/baselines/reference/exportAsNamespace2(module=es2015).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const b = 2;
99

1010
=== tests/cases/conformance/es2020/modules/1.ts ===
1111
export * as ns from './0';
12-
>ns : typeof ns
12+
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
1313

1414
ns.a;
1515
>ns.a : any

tests/baselines/reference/exportAsNamespace2(module=esnext).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const b = 2;
99

1010
=== tests/cases/conformance/es2020/modules/1.ts ===
1111
export * as ns from './0';
12-
>ns : typeof ns
12+
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
1313

1414
ns.a;
1515
>ns.a : any

tests/baselines/reference/exportAsNamespace2(module=system).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const b = 2;
99

1010
=== tests/cases/conformance/es2020/modules/1.ts ===
1111
export * as ns from './0';
12-
>ns : typeof ns
12+
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
1313

1414
ns.a;
1515
>ns.a : any

tests/baselines/reference/exportAsNamespace2(module=umd).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const b = 2;
99

1010
=== tests/cases/conformance/es2020/modules/1.ts ===
1111
export * as ns from './0';
12-
>ns : typeof ns
12+
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
1313

1414
ns.a;
1515
>ns.a : any

tests/baselines/reference/exportNamespace2.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export class A {}
44

55
=== tests/cases/conformance/externalModules/typeOnly/b.ts ===
66
export * as a from './a';
7-
>a : typeof a
7+
>a : typeof import("tests/cases/conformance/externalModules/typeOnly/a")
88

99
=== tests/cases/conformance/externalModules/typeOnly/c.ts ===
1010
import type { a } from './b';

tests/baselines/reference/exportNamespace3.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export type { A } from './a';
88

99
=== tests/cases/conformance/externalModules/typeOnly/c.ts ===
1010
export * as a from './b';
11-
>a : typeof a
11+
>a : typeof import("tests/cases/conformance/externalModules/typeOnly/b")
1212

1313
=== tests/cases/conformance/externalModules/typeOnly/d.ts ===
1414
import { a } from './c';

tests/baselines/reference/exportNamespace4.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export type * from './a'; // Grammar error
77
No type information for this code.
88
No type information for this code.=== tests/cases/conformance/externalModules/typeOnly/c.ts ===
99
export type * as ns from './a'; // Grammar error
10-
>ns : typeof ns
10+
>ns : typeof import("tests/cases/conformance/externalModules/typeOnly/a")
1111

1212
=== tests/cases/conformance/externalModules/typeOnly/d.ts ===
1313
import { A } from './b';

tests/baselines/reference/exportStarNotElided.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,5 @@ register("ok");
2727
export * from "./register";
2828
export * from "./data1";
2929
export * as aliased from "./data1";
30-
>aliased : typeof aliased
30+
>aliased : typeof import("tests/cases/compiler/data1")
3131

tests/baselines/reference/importHelpersWithExportStarAs(esmoduleinterop=false,module=amd).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export class A { }
44

55
=== tests/cases/compiler/b.ts ===
66
export * as a from "./a";
7-
>a : typeof a
7+
>a : typeof import("tests/cases/compiler/a")
88

99
=== tests/cases/compiler/tslib.d.ts ===
1010
declare module "tslib" {

tests/baselines/reference/importHelpersWithExportStarAs(esmoduleinterop=false,module=commonjs).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export class A { }
44

55
=== tests/cases/compiler/b.ts ===
66
export * as a from "./a";
7-
>a : typeof a
7+
>a : typeof import("tests/cases/compiler/a")
88

99
=== tests/cases/compiler/tslib.d.ts ===
1010
declare module "tslib" {

tests/baselines/reference/importHelpersWithExportStarAs(esmoduleinterop=false,module=es2015).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export class A { }
44

55
=== tests/cases/compiler/b.ts ===
66
export * as a from "./a";
7-
>a : typeof a
7+
>a : typeof import("tests/cases/compiler/a")
88

99
=== tests/cases/compiler/tslib.d.ts ===
1010
declare module "tslib" {

tests/baselines/reference/importHelpersWithExportStarAs(esmoduleinterop=false,module=es2020).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export class A { }
44

55
=== tests/cases/compiler/b.ts ===
66
export * as a from "./a";
7-
>a : typeof a
7+
>a : typeof import("tests/cases/compiler/a")
88

99
=== tests/cases/compiler/tslib.d.ts ===
1010
declare module "tslib" {

tests/baselines/reference/importHelpersWithExportStarAs(esmoduleinterop=false,module=system).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export class A { }
44

55
=== tests/cases/compiler/b.ts ===
66
export * as a from "./a";
7-
>a : typeof a
7+
>a : typeof import("tests/cases/compiler/a")
88

99
=== tests/cases/compiler/tslib.d.ts ===
1010
declare module "tslib" {

tests/baselines/reference/importHelpersWithExportStarAs(esmoduleinterop=true,module=amd).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export class A { }
44

55
=== tests/cases/compiler/b.ts ===
66
export * as a from "./a";
7-
>a : typeof a
7+
>a : typeof import("tests/cases/compiler/a")
88

99
=== tests/cases/compiler/tslib.d.ts ===
1010
declare module "tslib" {

tests/baselines/reference/importHelpersWithExportStarAs(esmoduleinterop=true,module=commonjs).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export class A { }
44

55
=== tests/cases/compiler/b.ts ===
66
export * as a from "./a";
7-
>a : typeof a
7+
>a : typeof import("tests/cases/compiler/a")
88

99
=== tests/cases/compiler/tslib.d.ts ===
1010
declare module "tslib" {

tests/baselines/reference/importHelpersWithExportStarAs(esmoduleinterop=true,module=es2015).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export class A { }
44

55
=== tests/cases/compiler/b.ts ===
66
export * as a from "./a";
7-
>a : typeof a
7+
>a : typeof import("tests/cases/compiler/a")
88

99
=== tests/cases/compiler/tslib.d.ts ===
1010
declare module "tslib" {

tests/baselines/reference/importHelpersWithExportStarAs(esmoduleinterop=true,module=es2020).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export class A { }
44

55
=== tests/cases/compiler/b.ts ===
66
export * as a from "./a";
7-
>a : typeof a
7+
>a : typeof import("tests/cases/compiler/a")
88

99
=== tests/cases/compiler/tslib.d.ts ===
1010
declare module "tslib" {

tests/baselines/reference/importHelpersWithExportStarAs(esmoduleinterop=true,module=system).types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export class A { }
44

55
=== tests/cases/compiler/b.ts ===
66
export * as a from "./a";
7-
>a : typeof a
7+
>a : typeof import("tests/cases/compiler/a")
88

99
=== tests/cases/compiler/tslib.d.ts ===
1010
declare module "tslib" {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// @target: esnext
2+
// @module: esnext
3+
// @declaration: true
4+
// @filename: sub.ts
5+
export function a() {}
6+
// @filename: index.ts
7+
export const x = add(import("./sub"));
8+
export * as Q from "./sub";
9+
declare function add<T>(x: Promise<T>): T;

0 commit comments

Comments
 (0)