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
This commit is contained in:
Wesley Wigham 2017-12-11 13:32:16 -05:00 committed by GitHub
parent 484758a3d3
commit d01f4d140a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 213 additions and 12 deletions

View File

@ -13123,6 +13123,12 @@ namespace ts {
return type;
}
function markAliasReferenced(symbol: Symbol, location: Node) {
if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(location) && !isConstEnumOrConstEnumOnlyModule(resolveAlias(symbol))) {
markAliasSymbolAsReferenced(symbol);
}
}
function checkIdentifier(node: Identifier): Type {
const symbol = getResolvedSymbol(node);
if (symbol === unknownSymbol) {
@ -13151,9 +13157,9 @@ namespace ts {
}
// We should only mark aliases as referenced if there isn't a local value declaration
// for the symbol.
if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveAlias(symbol))) {
markAliasSymbolAsReferenced(symbol);
// for the symbol. Also, don't mark any property access expression LHS - checkPropertyAccessExpression will handle that
if (!(node.parent && isPropertyAccessExpression(node.parent) && node.parent.expression === node)) {
markAliasReferenced(symbol, node);
}
const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol);
@ -15711,15 +15717,20 @@ namespace ts {
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) {
let propType: Type;
let leftSymbol = getNodeLinks(left) && getNodeLinks(left).resolvedSymbol;
const leftWasReferenced = leftSymbol && getSymbolLinks(leftSymbol).referenced;
const leftType = checkNonNullExpression(left);
const parentSymbol = getNodeLinks(left).resolvedSymbol;
const apparentType = getApparentType(getWidenedType(leftType));
if (isTypeAny(apparentType) || apparentType === silentNeverType) {
if (isIdentifier(left) && parentSymbol) {
markAliasReferenced(parentSymbol, node);
}
return apparentType;
}
const assignmentKind = getAssignmentTargetKind(node);
const prop = getPropertyOfType(apparentType, right.escapedText);
if (isIdentifier(left) && parentSymbol && !(prop && isConstEnumOrConstEnumOnlyModule(prop))) {
markAliasReferenced(parentSymbol, node);
}
if (!prop) {
const indexInfo = getIndexInfoOfType(apparentType, IndexKind.String);
if (!(indexInfo && indexInfo.type)) {
@ -15736,13 +15747,6 @@ namespace ts {
else {
checkPropertyNotUsedBeforeDeclaration(prop, node, right);
markPropertyAsReferenced(prop, node, left.kind === SyntaxKind.ThisKeyword);
// Reset the referenced-ness of the LHS expression if this access refers to a const enum or const enum only module
leftSymbol = getNodeLinks(left) && getNodeLinks(left).resolvedSymbol;
if (leftSymbol && !leftWasReferenced && getSymbolLinks(leftSymbol).referenced &&
!(isNonLocalAlias(leftSymbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(prop))
) {
getSymbolLinks(leftSymbol).referenced = undefined;
}
getNodeLinks(node).resolvedSymbol = prop;
checkPropertyAccessibility(node, left, apparentType, prop);
if (assignmentKind) {

View File

@ -0,0 +1,68 @@
//// [tests/cases/compiler/importAliasFromNamespace.ts] ////
//// [internal.ts]
namespace My.Internal {
export function getThing(): void {}
export const enum WhichThing {
A, B, C
}
}
//// [usage.ts]
/// <reference path="./internal.ts" />
namespace SomeOther.Thing {
import Internal = My.Internal;
export class Foo {
private _which: Internal.WhichThing;
constructor() {
Internal.getThing();
Internal.WhichThing.A ? "foo" : "bar";
}
}
}
//// [internal.js]
var My;
(function (My) {
var Internal;
(function (Internal) {
function getThing() { }
Internal.getThing = getThing;
})(Internal = My.Internal || (My.Internal = {}));
})(My || (My = {}));
//// [usage.js]
/// <reference path="./internal.ts" />
var SomeOther;
(function (SomeOther) {
var Thing;
(function (Thing) {
var Internal = My.Internal;
var Foo = /** @class */ (function () {
function Foo() {
Internal.getThing();
0 /* A */ ? "foo" : "bar";
}
return Foo;
}());
Thing.Foo = Foo;
})(Thing = SomeOther.Thing || (SomeOther.Thing = {}));
})(SomeOther || (SomeOther = {}));
//// [internal.d.ts]
declare namespace My.Internal {
function getThing(): void;
const enum WhichThing {
A = 0,
B = 1,
C = 2,
}
}
//// [usage.d.ts]
/// <reference path="internal.d.ts" />
declare namespace SomeOther.Thing {
class Foo {
private _which;
constructor();
}
}

View File

@ -0,0 +1,52 @@
=== tests/cases/compiler/usage.ts ===
/// <reference path="./internal.ts" />
namespace SomeOther.Thing {
>SomeOther : Symbol(SomeOther, Decl(usage.ts, 0, 0))
>Thing : Symbol(Thing, Decl(usage.ts, 1, 20))
import Internal = My.Internal;
>Internal : Symbol(Internal, Decl(usage.ts, 1, 27))
>My : Symbol(My, Decl(internal.ts, 0, 0))
>Internal : Symbol(Internal, Decl(internal.ts, 0, 13))
export class Foo {
>Foo : Symbol(Foo, Decl(usage.ts, 2, 34))
private _which: Internal.WhichThing;
>_which : Symbol(Foo._which, Decl(usage.ts, 3, 22))
>Internal : Symbol(Internal, Decl(usage.ts, 1, 27))
>WhichThing : Symbol(Internal.WhichThing, Decl(internal.ts, 1, 39))
constructor() {
Internal.getThing();
>Internal.getThing : Symbol(Internal.getThing, Decl(internal.ts, 0, 23))
>Internal : Symbol(Internal, Decl(usage.ts, 1, 27))
>getThing : Symbol(Internal.getThing, Decl(internal.ts, 0, 23))
Internal.WhichThing.A ? "foo" : "bar";
>Internal.WhichThing.A : Symbol(Internal.WhichThing.A, Decl(internal.ts, 2, 34))
>Internal.WhichThing : Symbol(Internal.WhichThing, Decl(internal.ts, 1, 39))
>Internal : Symbol(Internal, Decl(usage.ts, 1, 27))
>WhichThing : Symbol(Internal.WhichThing, Decl(internal.ts, 1, 39))
>A : Symbol(Internal.WhichThing.A, Decl(internal.ts, 2, 34))
}
}
}
=== tests/cases/compiler/internal.ts ===
namespace My.Internal {
>My : Symbol(My, Decl(internal.ts, 0, 0))
>Internal : Symbol(Internal, Decl(internal.ts, 0, 13))
export function getThing(): void {}
>getThing : Symbol(getThing, Decl(internal.ts, 0, 23))
export const enum WhichThing {
>WhichThing : Symbol(WhichThing, Decl(internal.ts, 1, 39))
A, B, C
>A : Symbol(WhichThing.A, Decl(internal.ts, 2, 34))
>B : Symbol(WhichThing.B, Decl(internal.ts, 3, 10))
>C : Symbol(WhichThing.C, Decl(internal.ts, 3, 13))
}
}

View File

@ -0,0 +1,56 @@
=== tests/cases/compiler/usage.ts ===
/// <reference path="./internal.ts" />
namespace SomeOther.Thing {
>SomeOther : typeof SomeOther
>Thing : typeof Thing
import Internal = My.Internal;
>Internal : typeof Internal
>My : typeof My
>Internal : typeof Internal
export class Foo {
>Foo : Foo
private _which: Internal.WhichThing;
>_which : Internal.WhichThing
>Internal : any
>WhichThing : Internal.WhichThing
constructor() {
Internal.getThing();
>Internal.getThing() : void
>Internal.getThing : () => void
>Internal : typeof Internal
>getThing : () => void
Internal.WhichThing.A ? "foo" : "bar";
>Internal.WhichThing.A ? "foo" : "bar" : "foo" | "bar"
>Internal.WhichThing.A : Internal.WhichThing.A
>Internal.WhichThing : typeof Internal.WhichThing
>Internal : typeof Internal
>WhichThing : typeof Internal.WhichThing
>A : Internal.WhichThing.A
>"foo" : "foo"
>"bar" : "bar"
}
}
}
=== tests/cases/compiler/internal.ts ===
namespace My.Internal {
>My : typeof My
>Internal : typeof Internal
export function getThing(): void {}
>getThing : () => void
export const enum WhichThing {
>WhichThing : WhichThing
A, B, C
>A : WhichThing.A
>B : WhichThing.B
>C : WhichThing.C
}
}

View File

@ -0,0 +1,21 @@
// @declaration: true
// @filename: internal.ts
namespace My.Internal {
export function getThing(): void {}
export const enum WhichThing {
A, B, C
}
}
// @filename: usage.ts
/// <reference path="./internal.ts" />
namespace SomeOther.Thing {
import Internal = My.Internal;
export class Foo {
private _which: Internal.WhichThing;
constructor() {
Internal.getThing();
Internal.WhichThing.A ? "foo" : "bar";
}
}
}