Skip to content

Commit d01f4d1

Browse files
authored
Reimplement #20320 differently to handle multiple check orders better (#20588)
* Reimplement #20320 less elegantly but handle odd check orders better * Consolidate 2 of 3 conditions
1 parent 484758a commit d01f4d1

File tree

5 files changed

+213
-12
lines changed

5 files changed

+213
-12
lines changed

src/compiler/checker.ts

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13123,6 +13123,12 @@ namespace ts {
1312313123
return type;
1312413124
}
1312513125

13126+
function markAliasReferenced(symbol: Symbol, location: Node) {
13127+
if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(location) && !isConstEnumOrConstEnumOnlyModule(resolveAlias(symbol))) {
13128+
markAliasSymbolAsReferenced(symbol);
13129+
}
13130+
}
13131+
1312613132
function checkIdentifier(node: Identifier): Type {
1312713133
const symbol = getResolvedSymbol(node);
1312813134
if (symbol === unknownSymbol) {
@@ -13151,9 +13157,9 @@ namespace ts {
1315113157
}
1315213158

1315313159
// We should only mark aliases as referenced if there isn't a local value declaration
13154-
// for the symbol.
13155-
if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveAlias(symbol))) {
13156-
markAliasSymbolAsReferenced(symbol);
13160+
// for the symbol. Also, don't mark any property access expression LHS - checkPropertyAccessExpression will handle that
13161+
if (!(node.parent && isPropertyAccessExpression(node.parent) && node.parent.expression === node)) {
13162+
markAliasReferenced(symbol, node);
1315713163
}
1315813164

1315913165
const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol);
@@ -15711,15 +15717,20 @@ namespace ts {
1571115717

1571215718
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) {
1571315719
let propType: Type;
15714-
let leftSymbol = getNodeLinks(left) && getNodeLinks(left).resolvedSymbol;
15715-
const leftWasReferenced = leftSymbol && getSymbolLinks(leftSymbol).referenced;
1571615720
const leftType = checkNonNullExpression(left);
15721+
const parentSymbol = getNodeLinks(left).resolvedSymbol;
1571715722
const apparentType = getApparentType(getWidenedType(leftType));
1571815723
if (isTypeAny(apparentType) || apparentType === silentNeverType) {
15724+
if (isIdentifier(left) && parentSymbol) {
15725+
markAliasReferenced(parentSymbol, node);
15726+
}
1571915727
return apparentType;
1572015728
}
1572115729
const assignmentKind = getAssignmentTargetKind(node);
1572215730
const prop = getPropertyOfType(apparentType, right.escapedText);
15731+
if (isIdentifier(left) && parentSymbol && !(prop && isConstEnumOrConstEnumOnlyModule(prop))) {
15732+
markAliasReferenced(parentSymbol, node);
15733+
}
1572315734
if (!prop) {
1572415735
const indexInfo = getIndexInfoOfType(apparentType, IndexKind.String);
1572515736
if (!(indexInfo && indexInfo.type)) {
@@ -15736,13 +15747,6 @@ namespace ts {
1573615747
else {
1573715748
checkPropertyNotUsedBeforeDeclaration(prop, node, right);
1573815749
markPropertyAsReferenced(prop, node, left.kind === SyntaxKind.ThisKeyword);
15739-
// Reset the referenced-ness of the LHS expression if this access refers to a const enum or const enum only module
15740-
leftSymbol = getNodeLinks(left) && getNodeLinks(left).resolvedSymbol;
15741-
if (leftSymbol && !leftWasReferenced && getSymbolLinks(leftSymbol).referenced &&
15742-
!(isNonLocalAlias(leftSymbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(prop))
15743-
) {
15744-
getSymbolLinks(leftSymbol).referenced = undefined;
15745-
}
1574615750
getNodeLinks(node).resolvedSymbol = prop;
1574715751
checkPropertyAccessibility(node, left, apparentType, prop);
1574815752
if (assignmentKind) {
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//// [tests/cases/compiler/importAliasFromNamespace.ts] ////
2+
3+
//// [internal.ts]
4+
namespace My.Internal {
5+
export function getThing(): void {}
6+
export const enum WhichThing {
7+
A, B, C
8+
}
9+
}
10+
11+
//// [usage.ts]
12+
/// <reference path="./internal.ts" />
13+
namespace SomeOther.Thing {
14+
import Internal = My.Internal;
15+
export class Foo {
16+
private _which: Internal.WhichThing;
17+
constructor() {
18+
Internal.getThing();
19+
Internal.WhichThing.A ? "foo" : "bar";
20+
}
21+
}
22+
}
23+
24+
//// [internal.js]
25+
var My;
26+
(function (My) {
27+
var Internal;
28+
(function (Internal) {
29+
function getThing() { }
30+
Internal.getThing = getThing;
31+
})(Internal = My.Internal || (My.Internal = {}));
32+
})(My || (My = {}));
33+
//// [usage.js]
34+
/// <reference path="./internal.ts" />
35+
var SomeOther;
36+
(function (SomeOther) {
37+
var Thing;
38+
(function (Thing) {
39+
var Internal = My.Internal;
40+
var Foo = /** @class */ (function () {
41+
function Foo() {
42+
Internal.getThing();
43+
0 /* A */ ? "foo" : "bar";
44+
}
45+
return Foo;
46+
}());
47+
Thing.Foo = Foo;
48+
})(Thing = SomeOther.Thing || (SomeOther.Thing = {}));
49+
})(SomeOther || (SomeOther = {}));
50+
51+
52+
//// [internal.d.ts]
53+
declare namespace My.Internal {
54+
function getThing(): void;
55+
const enum WhichThing {
56+
A = 0,
57+
B = 1,
58+
C = 2,
59+
}
60+
}
61+
//// [usage.d.ts]
62+
/// <reference path="internal.d.ts" />
63+
declare namespace SomeOther.Thing {
64+
class Foo {
65+
private _which;
66+
constructor();
67+
}
68+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
=== tests/cases/compiler/usage.ts ===
2+
/// <reference path="./internal.ts" />
3+
namespace SomeOther.Thing {
4+
>SomeOther : Symbol(SomeOther, Decl(usage.ts, 0, 0))
5+
>Thing : Symbol(Thing, Decl(usage.ts, 1, 20))
6+
7+
import Internal = My.Internal;
8+
>Internal : Symbol(Internal, Decl(usage.ts, 1, 27))
9+
>My : Symbol(My, Decl(internal.ts, 0, 0))
10+
>Internal : Symbol(Internal, Decl(internal.ts, 0, 13))
11+
12+
export class Foo {
13+
>Foo : Symbol(Foo, Decl(usage.ts, 2, 34))
14+
15+
private _which: Internal.WhichThing;
16+
>_which : Symbol(Foo._which, Decl(usage.ts, 3, 22))
17+
>Internal : Symbol(Internal, Decl(usage.ts, 1, 27))
18+
>WhichThing : Symbol(Internal.WhichThing, Decl(internal.ts, 1, 39))
19+
20+
constructor() {
21+
Internal.getThing();
22+
>Internal.getThing : Symbol(Internal.getThing, Decl(internal.ts, 0, 23))
23+
>Internal : Symbol(Internal, Decl(usage.ts, 1, 27))
24+
>getThing : Symbol(Internal.getThing, Decl(internal.ts, 0, 23))
25+
26+
Internal.WhichThing.A ? "foo" : "bar";
27+
>Internal.WhichThing.A : Symbol(Internal.WhichThing.A, Decl(internal.ts, 2, 34))
28+
>Internal.WhichThing : Symbol(Internal.WhichThing, Decl(internal.ts, 1, 39))
29+
>Internal : Symbol(Internal, Decl(usage.ts, 1, 27))
30+
>WhichThing : Symbol(Internal.WhichThing, Decl(internal.ts, 1, 39))
31+
>A : Symbol(Internal.WhichThing.A, Decl(internal.ts, 2, 34))
32+
}
33+
}
34+
}
35+
=== tests/cases/compiler/internal.ts ===
36+
namespace My.Internal {
37+
>My : Symbol(My, Decl(internal.ts, 0, 0))
38+
>Internal : Symbol(Internal, Decl(internal.ts, 0, 13))
39+
40+
export function getThing(): void {}
41+
>getThing : Symbol(getThing, Decl(internal.ts, 0, 23))
42+
43+
export const enum WhichThing {
44+
>WhichThing : Symbol(WhichThing, Decl(internal.ts, 1, 39))
45+
46+
A, B, C
47+
>A : Symbol(WhichThing.A, Decl(internal.ts, 2, 34))
48+
>B : Symbol(WhichThing.B, Decl(internal.ts, 3, 10))
49+
>C : Symbol(WhichThing.C, Decl(internal.ts, 3, 13))
50+
}
51+
}
52+
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
=== tests/cases/compiler/usage.ts ===
2+
/// <reference path="./internal.ts" />
3+
namespace SomeOther.Thing {
4+
>SomeOther : typeof SomeOther
5+
>Thing : typeof Thing
6+
7+
import Internal = My.Internal;
8+
>Internal : typeof Internal
9+
>My : typeof My
10+
>Internal : typeof Internal
11+
12+
export class Foo {
13+
>Foo : Foo
14+
15+
private _which: Internal.WhichThing;
16+
>_which : Internal.WhichThing
17+
>Internal : any
18+
>WhichThing : Internal.WhichThing
19+
20+
constructor() {
21+
Internal.getThing();
22+
>Internal.getThing() : void
23+
>Internal.getThing : () => void
24+
>Internal : typeof Internal
25+
>getThing : () => void
26+
27+
Internal.WhichThing.A ? "foo" : "bar";
28+
>Internal.WhichThing.A ? "foo" : "bar" : "foo" | "bar"
29+
>Internal.WhichThing.A : Internal.WhichThing.A
30+
>Internal.WhichThing : typeof Internal.WhichThing
31+
>Internal : typeof Internal
32+
>WhichThing : typeof Internal.WhichThing
33+
>A : Internal.WhichThing.A
34+
>"foo" : "foo"
35+
>"bar" : "bar"
36+
}
37+
}
38+
}
39+
=== tests/cases/compiler/internal.ts ===
40+
namespace My.Internal {
41+
>My : typeof My
42+
>Internal : typeof Internal
43+
44+
export function getThing(): void {}
45+
>getThing : () => void
46+
47+
export const enum WhichThing {
48+
>WhichThing : WhichThing
49+
50+
A, B, C
51+
>A : WhichThing.A
52+
>B : WhichThing.B
53+
>C : WhichThing.C
54+
}
55+
}
56+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// @declaration: true
2+
// @filename: internal.ts
3+
namespace My.Internal {
4+
export function getThing(): void {}
5+
export const enum WhichThing {
6+
A, B, C
7+
}
8+
}
9+
10+
// @filename: usage.ts
11+
/// <reference path="./internal.ts" />
12+
namespace SomeOther.Thing {
13+
import Internal = My.Internal;
14+
export class Foo {
15+
private _which: Internal.WhichThing;
16+
constructor() {
17+
Internal.getThing();
18+
Internal.WhichThing.A ? "foo" : "bar";
19+
}
20+
}
21+
}

0 commit comments

Comments
 (0)