Skip to content

Commit 576a733

Browse files
authored
For type emit, walk non-parent containers when those containers have aliases leading to the target (microsoft#24507)
1 parent 2cb4640 commit 576a733

7 files changed

+149
-7
lines changed

src/compiler/checker.ts

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2533,6 +2533,46 @@ namespace ts {
25332533
return getMergedSymbol(symbol.parent && getLateBoundSymbol(symbol.parent));
25342534
}
25352535

2536+
/**
2537+
* Attempts to find the symbol corresponding to the container a symbol is in - usually this
2538+
* is just its' `.parent`, but for locals, this value is `undefined`
2539+
*/
2540+
function getContainerOfSymbol(symbol: Symbol): Symbol | undefined {
2541+
const container = getParentOfSymbol(symbol);
2542+
if (container) {
2543+
return container;
2544+
}
2545+
const candidate = forEach(symbol.declarations, d => !isAmbientModule(d) && d.parent && hasNonGlobalAugmentationExternalModuleSymbol(d.parent) ? getSymbolOfNode(d.parent) : undefined);
2546+
if (!candidate) {
2547+
return undefined;
2548+
}
2549+
const alias = getAliasForSymbolInContainer(candidate, symbol);
2550+
return alias ? candidate : undefined;
2551+
}
2552+
2553+
function getAliasForSymbolInContainer(container: Symbol, symbol: Symbol) {
2554+
if (container === getParentOfSymbol(symbol)) {
2555+
// fast path, `symbol` is either already the alias or isn't aliased
2556+
return symbol;
2557+
}
2558+
const exports = getExportsOfSymbol(container);
2559+
const quick = exports.get(symbol.escapedName);
2560+
if (quick && symbolRefersToTarget(quick)) {
2561+
return quick;
2562+
}
2563+
return forEachEntry(exports, exported => {
2564+
if (symbolRefersToTarget(exported)) {
2565+
return exported;
2566+
}
2567+
});
2568+
2569+
function symbolRefersToTarget(s: Symbol) {
2570+
if (s === symbol || resolveSymbol(s) === symbol || resolveSymbol(s) === resolveSymbol(symbol)) {
2571+
return s;
2572+
}
2573+
}
2574+
}
2575+
25362576
function getExportSymbolOfValueSymbolIfExported(symbol: Symbol): Symbol;
25372577
function getExportSymbolOfValueSymbolIfExported(symbol: Symbol | undefined): Symbol | undefined;
25382578
function getExportSymbolOfValueSymbolIfExported(symbol: Symbol | undefined): Symbol | undefined {
@@ -2838,7 +2878,7 @@ namespace ts {
28382878
// But it can't, hence the accessible is going to be undefined, but that doesn't mean m.c is inaccessible
28392879
// It is accessible if the parent m is accessible because then m.c can be accessed through qualification
28402880
meaningToLook = getQualifiedLeftMeaning(meaning);
2841-
symbol = getParentOfSymbol(symbol);
2881+
symbol = getContainerOfSymbol(symbol);
28422882
}
28432883

28442884
// This could be a symbol that is not exported in the external module
@@ -3729,12 +3769,12 @@ namespace ts {
37293769
needsQualification(accessibleSymbolChain[0], context.enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) {
37303770

37313771
// Go up and add our parent.
3732-
const parent = getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol);
3772+
const parent = getContainerOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol);
37333773
if (parent) {
37343774
const parentChain = getSymbolChain(parent, getQualifiedLeftMeaning(meaning), /*endOfChain*/ false);
37353775
if (parentChain) {
37363776
parentSymbol = parent;
3737-
accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [symbol]);
3777+
accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [getAliasForSymbolInContainer(parent, symbol) || symbol]);
37383778
}
37393779
}
37403780
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//// [tests/cases/compiler/allowSyntheticDefaultImportsCanPaintCrossModuleDeclaration.ts] ////
2+
3+
//// [color.ts]
4+
interface Color {
5+
c: string;
6+
}
7+
export default Color;
8+
//// [file1.ts]
9+
import Color from "./color";
10+
export declare function styled(): Color;
11+
//// [file2.ts]
12+
import { styled } from "./file1";
13+
export const A = styled();
14+
15+
//// [color.js]
16+
"use strict";
17+
exports.__esModule = true;
18+
//// [file1.js]
19+
"use strict";
20+
exports.__esModule = true;
21+
//// [file2.js]
22+
"use strict";
23+
exports.__esModule = true;
24+
var file1_1 = require("./file1");
25+
exports.A = file1_1.styled();
26+
27+
28+
//// [color.d.ts]
29+
interface Color {
30+
c: string;
31+
}
32+
export default Color;
33+
//// [file1.d.ts]
34+
import Color from "./color";
35+
export declare function styled(): Color;
36+
//// [file2.d.ts]
37+
export declare const A: import("./color").default;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
=== tests/cases/compiler/color.ts ===
2+
interface Color {
3+
>Color : Symbol(Color, Decl(color.ts, 0, 0))
4+
5+
c: string;
6+
>c : Symbol(Color.c, Decl(color.ts, 0, 17))
7+
}
8+
export default Color;
9+
>Color : Symbol(Color, Decl(color.ts, 0, 0))
10+
11+
=== tests/cases/compiler/file1.ts ===
12+
import Color from "./color";
13+
>Color : Symbol(Color, Decl(file1.ts, 0, 6))
14+
15+
export declare function styled(): Color;
16+
>styled : Symbol(styled, Decl(file1.ts, 0, 28))
17+
>Color : Symbol(Color, Decl(file1.ts, 0, 6))
18+
19+
=== tests/cases/compiler/file2.ts ===
20+
import { styled } from "./file1";
21+
>styled : Symbol(styled, Decl(file2.ts, 0, 8))
22+
23+
export const A = styled();
24+
>A : Symbol(A, Decl(file2.ts, 1, 12))
25+
>styled : Symbol(styled, Decl(file2.ts, 0, 8))
26+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
=== tests/cases/compiler/color.ts ===
2+
interface Color {
3+
>Color : Color
4+
5+
c: string;
6+
>c : string
7+
}
8+
export default Color;
9+
>Color : Color
10+
11+
=== tests/cases/compiler/file1.ts ===
12+
import Color from "./color";
13+
>Color : any
14+
15+
export declare function styled(): Color;
16+
>styled : () => Color
17+
>Color : Color
18+
19+
=== tests/cases/compiler/file2.ts ===
20+
import { styled } from "./file1";
21+
>styled : () => import("tests/cases/compiler/color").default
22+
23+
export const A = styled();
24+
>A : import("tests/cases/compiler/color").default
25+
>styled() : import("tests/cases/compiler/color").default
26+
>styled : () => import("tests/cases/compiler/color").default
27+

tests/baselines/reference/importTypeGenericTypes.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ export const x: import("./foo")<{x: number}> = { x: 0, y: 0, data: {x: 12} };
8989
>12 : 12
9090

9191
export let y: import("./foo2").Bar.I<{x: number}> = { a: "", b: 0, data: {x: 12} };
92-
>y : Bar.I<{ x: number; }>
92+
>y : import("tests/cases/conformance/types/import/foo2").Bar.I<{ x: number; }>
9393
>Bar : any
94-
>I : Bar.I<T>
94+
>I : import("tests/cases/conformance/types/import/foo2").Bar.I<T>
9595
>x : number
9696
>{ a: "", b: 0, data: {x: 12} } : { a: string; b: number; data: { x: number; }; }
9797
>a : string

tests/baselines/reference/importTypeLocal.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ export const x: import("./foo") = { x: 0, y: 0 };
6666
>0 : 0
6767

6868
export let y: import("./foo2").Bar.I = { a: "", b: 0 };
69-
>y : Bar.I
69+
>y : import("tests/cases/conformance/types/import/foo2").Bar.I
7070
>Bar : any
71-
>I : Bar.I
71+
>I : import("tests/cases/conformance/types/import/foo2").Bar.I
7272
>{ a: "", b: 0 } : { a: string; b: number; }
7373
>a : string
7474
>"" : ""
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// @declaration: true
2+
// @filename: color.ts
3+
interface Color {
4+
c: string;
5+
}
6+
export default Color;
7+
// @filename: file1.ts
8+
import Color from "./color";
9+
export declare function styled(): Color;
10+
// @filename: file2.ts
11+
import { styled } from "./file1";
12+
export const A = styled();

0 commit comments

Comments
 (0)