Elide import namespace from which only const enums are used (#20320)

This commit is contained in:
Wesley Wigham 2017-11-29 16:36:17 -08:00 committed by GitHub
parent 78250ec58f
commit a625dec58a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 144 additions and 0 deletions

View file

@ -15581,6 +15581,8 @@ 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 apparentType = getApparentType(getWidenedType(leftType));
if (isTypeAny(apparentType) || apparentType === silentNeverType) {
@ -15604,6 +15606,13 @@ 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) {
@ -24691,6 +24700,11 @@ namespace ts {
if (symbol && getSymbolLinks(symbol).referenced) {
return true;
}
const target = getSymbolLinks(symbol).target;
if (target && getModifierFlags(node) & ModifierFlags.Export && target.flags & SymbolFlags.Value) {
// An `export import ... =` of a value symbol is always considered referenced
return true;
}
}
if (checkChildren) {

View file

@ -0,0 +1,34 @@
//// [tests/cases/compiler/constEnumNamespaceReferenceCausesNoImport.ts] ////
//// [foo.ts]
export const enum ConstFooEnum {
Some,
Values,
Here
};
export function fooFunc(): void { /* removed */ }
//// [index.ts]
import * as Foo from "./foo";
function check(x: Foo.ConstFooEnum): void {
switch (x) {
case Foo.ConstFooEnum.Some:
break;
}
}
//// [foo.js]
"use strict";
exports.__esModule = true;
;
function fooFunc() { }
exports.fooFunc = fooFunc;
//// [index.js]
"use strict";
exports.__esModule = true;
function check(x) {
switch (x) {
case 0 /* Some */:
break;
}
}

View file

@ -0,0 +1,40 @@
=== tests/cases/compiler/foo.ts ===
export const enum ConstFooEnum {
>ConstFooEnum : Symbol(ConstFooEnum, Decl(foo.ts, 0, 0))
Some,
>Some : Symbol(ConstFooEnum.Some, Decl(foo.ts, 0, 32))
Values,
>Values : Symbol(ConstFooEnum.Values, Decl(foo.ts, 1, 9))
Here
>Here : Symbol(ConstFooEnum.Here, Decl(foo.ts, 2, 11))
};
export function fooFunc(): void { /* removed */ }
>fooFunc : Symbol(fooFunc, Decl(foo.ts, 4, 2))
=== tests/cases/compiler/index.ts ===
import * as Foo from "./foo";
>Foo : Symbol(Foo, Decl(index.ts, 0, 6))
function check(x: Foo.ConstFooEnum): void {
>check : Symbol(check, Decl(index.ts, 0, 29))
>x : Symbol(x, Decl(index.ts, 2, 15))
>Foo : Symbol(Foo, Decl(index.ts, 0, 6))
>ConstFooEnum : Symbol(Foo.ConstFooEnum, Decl(foo.ts, 0, 0))
switch (x) {
>x : Symbol(x, Decl(index.ts, 2, 15))
case Foo.ConstFooEnum.Some:
>Foo.ConstFooEnum.Some : Symbol(Foo.ConstFooEnum.Some, Decl(foo.ts, 0, 32))
>Foo.ConstFooEnum : Symbol(Foo.ConstFooEnum, Decl(foo.ts, 0, 0))
>Foo : Symbol(Foo, Decl(index.ts, 0, 6))
>ConstFooEnum : Symbol(Foo.ConstFooEnum, Decl(foo.ts, 0, 0))
>Some : Symbol(Foo.ConstFooEnum.Some, Decl(foo.ts, 0, 32))
break;
}
}

View file

@ -0,0 +1,40 @@
=== tests/cases/compiler/foo.ts ===
export const enum ConstFooEnum {
>ConstFooEnum : ConstFooEnum
Some,
>Some : ConstFooEnum.Some
Values,
>Values : ConstFooEnum.Values
Here
>Here : ConstFooEnum.Here
};
export function fooFunc(): void { /* removed */ }
>fooFunc : () => void
=== tests/cases/compiler/index.ts ===
import * as Foo from "./foo";
>Foo : typeof Foo
function check(x: Foo.ConstFooEnum): void {
>check : (x: Foo.ConstFooEnum) => void
>x : Foo.ConstFooEnum
>Foo : any
>ConstFooEnum : Foo.ConstFooEnum
switch (x) {
>x : Foo.ConstFooEnum
case Foo.ConstFooEnum.Some:
>Foo.ConstFooEnum.Some : Foo.ConstFooEnum.Some
>Foo.ConstFooEnum : typeof Foo.ConstFooEnum
>Foo : typeof Foo
>ConstFooEnum : typeof Foo.ConstFooEnum
>Some : Foo.ConstFooEnum.Some
break;
}
}

View file

@ -0,0 +1,16 @@
// @filename: foo.ts
export const enum ConstFooEnum {
Some,
Values,
Here
};
export function fooFunc(): void { /* removed */ }
// @filename: index.ts
import * as Foo from "./foo";
function check(x: Foo.ConstFooEnum): void {
switch (x) {
case Foo.ConstFooEnum.Some:
break;
}
}