mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-28 15:06:29 -05:00
For type emit, walk non-parent containers when those containers have aliases leading to the target (#24507)
This commit is contained in:
@@ -2533,6 +2533,46 @@ namespace ts {
|
||||
return getMergedSymbol(symbol.parent && getLateBoundSymbol(symbol.parent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find the symbol corresponding to the container a symbol is in - usually this
|
||||
* is just its' `.parent`, but for locals, this value is `undefined`
|
||||
*/
|
||||
function getContainerOfSymbol(symbol: Symbol): Symbol | undefined {
|
||||
const container = getParentOfSymbol(symbol);
|
||||
if (container) {
|
||||
return container;
|
||||
}
|
||||
const candidate = forEach(symbol.declarations, d => !isAmbientModule(d) && d.parent && hasNonGlobalAugmentationExternalModuleSymbol(d.parent) ? getSymbolOfNode(d.parent) : undefined);
|
||||
if (!candidate) {
|
||||
return undefined;
|
||||
}
|
||||
const alias = getAliasForSymbolInContainer(candidate, symbol);
|
||||
return alias ? candidate : undefined;
|
||||
}
|
||||
|
||||
function getAliasForSymbolInContainer(container: Symbol, symbol: Symbol) {
|
||||
if (container === getParentOfSymbol(symbol)) {
|
||||
// fast path, `symbol` is either already the alias or isn't aliased
|
||||
return symbol;
|
||||
}
|
||||
const exports = getExportsOfSymbol(container);
|
||||
const quick = exports.get(symbol.escapedName);
|
||||
if (quick && symbolRefersToTarget(quick)) {
|
||||
return quick;
|
||||
}
|
||||
return forEachEntry(exports, exported => {
|
||||
if (symbolRefersToTarget(exported)) {
|
||||
return exported;
|
||||
}
|
||||
});
|
||||
|
||||
function symbolRefersToTarget(s: Symbol) {
|
||||
if (s === symbol || resolveSymbol(s) === symbol || resolveSymbol(s) === resolveSymbol(symbol)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getExportSymbolOfValueSymbolIfExported(symbol: Symbol): Symbol;
|
||||
function getExportSymbolOfValueSymbolIfExported(symbol: Symbol | undefined): Symbol | undefined;
|
||||
function getExportSymbolOfValueSymbolIfExported(symbol: Symbol | undefined): Symbol | undefined {
|
||||
@@ -2838,7 +2878,7 @@ namespace ts {
|
||||
// But it can't, hence the accessible is going to be undefined, but that doesn't mean m.c is inaccessible
|
||||
// It is accessible if the parent m is accessible because then m.c can be accessed through qualification
|
||||
meaningToLook = getQualifiedLeftMeaning(meaning);
|
||||
symbol = getParentOfSymbol(symbol);
|
||||
symbol = getContainerOfSymbol(symbol);
|
||||
}
|
||||
|
||||
// This could be a symbol that is not exported in the external module
|
||||
@@ -3729,12 +3769,12 @@ namespace ts {
|
||||
needsQualification(accessibleSymbolChain[0], context.enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) {
|
||||
|
||||
// Go up and add our parent.
|
||||
const parent = getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol);
|
||||
const parent = getContainerOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol);
|
||||
if (parent) {
|
||||
const parentChain = getSymbolChain(parent, getQualifiedLeftMeaning(meaning), /*endOfChain*/ false);
|
||||
if (parentChain) {
|
||||
parentSymbol = parent;
|
||||
accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [symbol]);
|
||||
accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [getAliasForSymbolInContainer(parent, symbol) || symbol]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
//// [tests/cases/compiler/allowSyntheticDefaultImportsCanPaintCrossModuleDeclaration.ts] ////
|
||||
|
||||
//// [color.ts]
|
||||
interface Color {
|
||||
c: string;
|
||||
}
|
||||
export default Color;
|
||||
//// [file1.ts]
|
||||
import Color from "./color";
|
||||
export declare function styled(): Color;
|
||||
//// [file2.ts]
|
||||
import { styled } from "./file1";
|
||||
export const A = styled();
|
||||
|
||||
//// [color.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
//// [file1.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
//// [file2.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
var file1_1 = require("./file1");
|
||||
exports.A = file1_1.styled();
|
||||
|
||||
|
||||
//// [color.d.ts]
|
||||
interface Color {
|
||||
c: string;
|
||||
}
|
||||
export default Color;
|
||||
//// [file1.d.ts]
|
||||
import Color from "./color";
|
||||
export declare function styled(): Color;
|
||||
//// [file2.d.ts]
|
||||
export declare const A: import("./color").default;
|
||||
@@ -0,0 +1,26 @@
|
||||
=== tests/cases/compiler/color.ts ===
|
||||
interface Color {
|
||||
>Color : Symbol(Color, Decl(color.ts, 0, 0))
|
||||
|
||||
c: string;
|
||||
>c : Symbol(Color.c, Decl(color.ts, 0, 17))
|
||||
}
|
||||
export default Color;
|
||||
>Color : Symbol(Color, Decl(color.ts, 0, 0))
|
||||
|
||||
=== tests/cases/compiler/file1.ts ===
|
||||
import Color from "./color";
|
||||
>Color : Symbol(Color, Decl(file1.ts, 0, 6))
|
||||
|
||||
export declare function styled(): Color;
|
||||
>styled : Symbol(styled, Decl(file1.ts, 0, 28))
|
||||
>Color : Symbol(Color, Decl(file1.ts, 0, 6))
|
||||
|
||||
=== tests/cases/compiler/file2.ts ===
|
||||
import { styled } from "./file1";
|
||||
>styled : Symbol(styled, Decl(file2.ts, 0, 8))
|
||||
|
||||
export const A = styled();
|
||||
>A : Symbol(A, Decl(file2.ts, 1, 12))
|
||||
>styled : Symbol(styled, Decl(file2.ts, 0, 8))
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
=== tests/cases/compiler/color.ts ===
|
||||
interface Color {
|
||||
>Color : Color
|
||||
|
||||
c: string;
|
||||
>c : string
|
||||
}
|
||||
export default Color;
|
||||
>Color : Color
|
||||
|
||||
=== tests/cases/compiler/file1.ts ===
|
||||
import Color from "./color";
|
||||
>Color : any
|
||||
|
||||
export declare function styled(): Color;
|
||||
>styled : () => Color
|
||||
>Color : Color
|
||||
|
||||
=== tests/cases/compiler/file2.ts ===
|
||||
import { styled } from "./file1";
|
||||
>styled : () => import("tests/cases/compiler/color").default
|
||||
|
||||
export const A = styled();
|
||||
>A : import("tests/cases/compiler/color").default
|
||||
>styled() : import("tests/cases/compiler/color").default
|
||||
>styled : () => import("tests/cases/compiler/color").default
|
||||
|
||||
@@ -89,9 +89,9 @@ export const x: import("./foo")<{x: number}> = { x: 0, y: 0, data: {x: 12} };
|
||||
>12 : 12
|
||||
|
||||
export let y: import("./foo2").Bar.I<{x: number}> = { a: "", b: 0, data: {x: 12} };
|
||||
>y : Bar.I<{ x: number; }>
|
||||
>y : import("tests/cases/conformance/types/import/foo2").Bar.I<{ x: number; }>
|
||||
>Bar : any
|
||||
>I : Bar.I<T>
|
||||
>I : import("tests/cases/conformance/types/import/foo2").Bar.I<T>
|
||||
>x : number
|
||||
>{ a: "", b: 0, data: {x: 12} } : { a: string; b: number; data: { x: number; }; }
|
||||
>a : string
|
||||
|
||||
@@ -66,9 +66,9 @@ export const x: import("./foo") = { x: 0, y: 0 };
|
||||
>0 : 0
|
||||
|
||||
export let y: import("./foo2").Bar.I = { a: "", b: 0 };
|
||||
>y : Bar.I
|
||||
>y : import("tests/cases/conformance/types/import/foo2").Bar.I
|
||||
>Bar : any
|
||||
>I : Bar.I
|
||||
>I : import("tests/cases/conformance/types/import/foo2").Bar.I
|
||||
>{ a: "", b: 0 } : { a: string; b: number; }
|
||||
>a : string
|
||||
>"" : ""
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// @declaration: true
|
||||
// @filename: color.ts
|
||||
interface Color {
|
||||
c: string;
|
||||
}
|
||||
export default Color;
|
||||
// @filename: file1.ts
|
||||
import Color from "./color";
|
||||
export declare function styled(): Color;
|
||||
// @filename: file2.ts
|
||||
import { styled } from "./file1";
|
||||
export const A = styled();
|
||||
Reference in New Issue
Block a user