Skip to content

Commit c24f75f

Browse files
committed
defer decision whether import used on the right side of import declaration should be considered referenced
1 parent 90a9b34 commit c24f75f

5 files changed

Lines changed: 166 additions & 11 deletions

File tree

src/compiler/checker.ts

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4734,14 +4734,47 @@ module ts {
47344734
return type;
47354735
}
47364736
}
4737+
/*Transitively mark all linked imports as referenced*/
4738+
function markLinkedImportsAsReferenced(node: ImportDeclaration): void {
4739+
var nodeLinks = getNodeLinks(node);
4740+
while (nodeLinks.importOnRightSide) {
4741+
var rightSide = nodeLinks.importOnRightSide;
4742+
nodeLinks.importOnRightSide = undefined;
4743+
4744+
getSymbolLinks(rightSide).referenced = true;
4745+
nodeLinks = getNodeLinks(rightSide.declarations[0])
4746+
}
4747+
}
47374748

47384749
function checkIdentifier(node: Identifier): Type {
47394750
var symbol = getResolvedSymbol(node);
47404751

47414752
if (symbol.flags & SymbolFlags.Import) {
4742-
// Mark the import as referenced so that we emit it in the final .js file.
4743-
// exception: identifiers that appear in type queries, const enums, modules that contain only const enums
4744-
getSymbolLinks(symbol).referenced = getSymbolLinks(symbol).referenced || (!isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveImport(symbol)));
4753+
var symbolLinks = getSymbolLinks(symbol);
4754+
if (!symbolLinks.referenced) {
4755+
var importOrExportAssignment = getLeftSideOfImportOrExportAssignment(node);
4756+
4757+
// decision about whether import is referenced can be made now if
4758+
// - import that are used anywhere except right side of import declarations
4759+
// - imports that are used on the right side of exported import declarations
4760+
// for other cases defer decision until the check of left side
4761+
if (!importOrExportAssignment ||
4762+
(importOrExportAssignment.flags & NodeFlags.Export) ||
4763+
(importOrExportAssignment.kind === SyntaxKind.ExportAssignment)) {
4764+
// Mark the import as referenced so that we emit it in the final .js file.
4765+
// exception: identifiers that appear in type queries, const enums, modules that contain only const enums
4766+
symbolLinks.referenced = !isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveImport(symbol));
4767+
}
4768+
else {
4769+
var nodeLinks = getNodeLinks(importOrExportAssignment);
4770+
Debug.assert(!nodeLinks.importOnRightSide);
4771+
nodeLinks.importOnRightSide = symbol;
4772+
}
4773+
}
4774+
4775+
if (symbolLinks.referenced) {
4776+
markLinkedImportsAsReferenced(<ImportDeclaration>symbol.declarations[0]);
4777+
}
47454778
}
47464779

47474780
checkCollisionWithCapturedSuperVariable(node, node);
@@ -8872,6 +8905,8 @@ module ts {
88728905
if (symbol && symbol.flags & SymbolFlags.Import) {
88738906
// Mark the import as referenced so that we emit it in the final .js file.
88748907
getSymbolLinks(symbol).referenced = true;
8908+
// mark any import declarations that depend upon this import as referenced
8909+
markLinkedImportsAsReferenced(<ImportDeclaration>symbol.declarations[0])
88758910
}
88768911
}
88778912

@@ -9097,19 +9132,24 @@ module ts {
90979132
return false;
90989133
}
90999134

9100-
function isInRightSideOfImportOrExportAssignment(node: EntityName) {
9101-
while (node.parent.kind === SyntaxKind.QualifiedName) {
9102-
node = <QualifiedName>node.parent;
9135+
function getLeftSideOfImportOrExportAssignment(nodeOnRightSide: EntityName): ImportDeclaration | ExportAssignment {
9136+
while (nodeOnRightSide.parent.kind === SyntaxKind.QualifiedName) {
9137+
nodeOnRightSide = <QualifiedName>nodeOnRightSide.parent;
91039138
}
91049139

9105-
if (node.parent.kind === SyntaxKind.ImportDeclaration) {
9106-
return (<ImportDeclaration>node.parent).moduleReference === node;
9140+
if (nodeOnRightSide.parent.kind === SyntaxKind.ImportDeclaration) {
9141+
return (<ImportDeclaration>nodeOnRightSide.parent).moduleReference === nodeOnRightSide && <ImportDeclaration>nodeOnRightSide.parent;
91079142
}
9108-
if (node.parent.kind === SyntaxKind.ExportAssignment) {
9109-
return (<ExportAssignment>node.parent).exportName === node;
9143+
9144+
if (nodeOnRightSide.parent.kind === SyntaxKind.ExportAssignment) {
9145+
return (<ExportAssignment>nodeOnRightSide.parent).exportName === nodeOnRightSide && <ExportAssignment>nodeOnRightSide.parent;
91109146
}
91119147

9112-
return false;
9148+
return undefined;
9149+
}
9150+
9151+
function isInRightSideOfImportOrExportAssignment(node: EntityName) {
9152+
return getLeftSideOfImportOrExportAssignment(node) !== undefined;
91139153
}
91149154

91159155
function isRightSideOfQualifiedNameOrPropertyAccess(node: Node) {

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,7 @@ module ts {
12161216
isVisible?: boolean; // Is this node visible
12171217
localModuleName?: string; // Local name for module instance
12181218
assignmentChecks?: Map<boolean>; // Cache of assignment checks
1219+
importOnRightSide?: Symbol; // for import declarations - import that appear on the right side
12191220
}
12201221

12211222
export const enum TypeFlags {
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//// [tests/cases/compiler/importedAliasesInTypePositions.ts] ////
2+
3+
//// [file1.ts]
4+
export module elaborate.nested.mod.name {
5+
export class ReferredTo {
6+
doSomething(): void {
7+
}
8+
}
9+
}
10+
11+
//// [file2.ts]
12+
import RT_ALIAS = require("file1");
13+
import ReferredTo = RT_ALIAS.elaborate.nested.mod.name.ReferredTo;
14+
15+
export module ImportingModule {
16+
class UsesReferredType {
17+
constructor(private referred: ReferredTo) { }
18+
}
19+
}
20+
21+
//// [file1.js]
22+
define(["require", "exports"], function (require, exports) {
23+
var elaborate;
24+
(function (elaborate) {
25+
var nested;
26+
(function (nested) {
27+
var mod;
28+
(function (mod) {
29+
var name;
30+
(function (name) {
31+
var ReferredTo = (function () {
32+
function ReferredTo() {
33+
}
34+
ReferredTo.prototype.doSomething = function () {
35+
};
36+
return ReferredTo;
37+
})();
38+
name.ReferredTo = ReferredTo;
39+
})(name = mod.name || (mod.name = {}));
40+
})(mod = nested.mod || (nested.mod = {}));
41+
})(nested = elaborate.nested || (elaborate.nested = {}));
42+
})(elaborate = exports.elaborate || (exports.elaborate = {}));
43+
});
44+
//// [file2.js]
45+
define(["require", "exports"], function (require, exports) {
46+
var ImportingModule;
47+
(function (ImportingModule) {
48+
var UsesReferredType = (function () {
49+
function UsesReferredType(referred) {
50+
this.referred = referred;
51+
}
52+
return UsesReferredType;
53+
})();
54+
})(ImportingModule = exports.ImportingModule || (exports.ImportingModule = {}));
55+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
=== tests/cases/compiler/file2.ts ===
2+
import RT_ALIAS = require("file1");
3+
>RT_ALIAS : typeof RT_ALIAS
4+
5+
import ReferredTo = RT_ALIAS.elaborate.nested.mod.name.ReferredTo;
6+
>ReferredTo : typeof ReferredTo
7+
>RT_ALIAS : typeof RT_ALIAS
8+
>elaborate : typeof RT_ALIAS.elaborate
9+
>nested : typeof RT_ALIAS.elaborate.nested
10+
>mod : typeof RT_ALIAS.elaborate.nested.mod
11+
>name : typeof RT_ALIAS.elaborate.nested.mod.name
12+
>ReferredTo : ReferredTo
13+
14+
export module ImportingModule {
15+
>ImportingModule : typeof ImportingModule
16+
17+
class UsesReferredType {
18+
>UsesReferredType : UsesReferredType
19+
20+
constructor(private referred: ReferredTo) { }
21+
>referred : ReferredTo
22+
>ReferredTo : ReferredTo
23+
}
24+
}
25+
=== tests/cases/compiler/file1.ts ===
26+
export module elaborate.nested.mod.name {
27+
>elaborate : typeof elaborate
28+
>nested : typeof nested
29+
>mod : typeof mod
30+
>name : typeof name
31+
32+
export class ReferredTo {
33+
>ReferredTo : ReferredTo
34+
35+
doSomething(): void {
36+
>doSomething : () => void
37+
}
38+
}
39+
}
40+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// @module:amd
2+
// @Filename: file1.ts
3+
export module elaborate.nested.mod.name {
4+
export class ReferredTo {
5+
doSomething(): void {
6+
}
7+
}
8+
}
9+
10+
// @Filename: file2.ts
11+
// @module: amd
12+
import RT_ALIAS = require("file1");
13+
import ReferredTo = RT_ALIAS.elaborate.nested.mod.name.ReferredTo;
14+
15+
export module ImportingModule {
16+
class UsesReferredType {
17+
constructor(private referred: ReferredTo) { }
18+
}
19+
}

0 commit comments

Comments
 (0)