Skip to content

Commit 59c73c5

Browse files
committed
Merge pull request microsoft#1466 from Microsoft/linked_imports
defer decision whether import used on the right side of import declarati...
2 parents 1eba8db + 5b38cb9 commit 59c73c5

5 files changed

Lines changed: 168 additions & 11 deletions

File tree

src/compiler/checker.ts

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4734,14 +4734,49 @@ 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+
Debug.assert((rightSide.flags & SymbolFlags.Import) !== 0);
4746+
4747+
nodeLinks = getNodeLinks(getDeclarationOfKind(rightSide, SyntaxKind.ImportDeclaration))
4748+
}
4749+
}
47374750

47384751
function checkIdentifier(node: Identifier): Type {
47394752
var symbol = getResolvedSymbol(node);
47404753

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

47474782
checkCollisionWithCapturedSuperVariable(node, node);
@@ -8872,6 +8907,8 @@ module ts {
88728907
if (symbol && symbol.flags & SymbolFlags.Import) {
88738908
// Mark the import as referenced so that we emit it in the final .js file.
88748909
getSymbolLinks(symbol).referenced = true;
8910+
// mark any import declarations that depend upon this import as referenced
8911+
markLinkedImportsAsReferenced(<ImportDeclaration>getDeclarationOfKind(symbol, SyntaxKind.ImportDeclaration))
88758912
}
88768913
}
88778914

@@ -9097,19 +9134,24 @@ module ts {
90979134
return false;
90989135
}
90999136

9100-
function isInRightSideOfImportOrExportAssignment(node: EntityName) {
9101-
while (node.parent.kind === SyntaxKind.QualifiedName) {
9102-
node = <QualifiedName>node.parent;
9137+
function getLeftSideOfImportOrExportAssignment(nodeOnRightSide: EntityName): ImportDeclaration | ExportAssignment {
9138+
while (nodeOnRightSide.parent.kind === SyntaxKind.QualifiedName) {
9139+
nodeOnRightSide = <QualifiedName>nodeOnRightSide.parent;
91039140
}
91049141

9105-
if (node.parent.kind === SyntaxKind.ImportDeclaration) {
9106-
return (<ImportDeclaration>node.parent).moduleReference === node;
9142+
if (nodeOnRightSide.parent.kind === SyntaxKind.ImportDeclaration) {
9143+
return (<ImportDeclaration>nodeOnRightSide.parent).moduleReference === nodeOnRightSide && <ImportDeclaration>nodeOnRightSide.parent;
91079144
}
9108-
if (node.parent.kind === SyntaxKind.ExportAssignment) {
9109-
return (<ExportAssignment>node.parent).exportName === node;
9145+
9146+
if (nodeOnRightSide.parent.kind === SyntaxKind.ExportAssignment) {
9147+
return (<ExportAssignment>nodeOnRightSide.parent).exportName === nodeOnRightSide && <ExportAssignment>nodeOnRightSide.parent;
91109148
}
91119149

9112-
return false;
9150+
return undefined;
9151+
}
9152+
9153+
function isInRightSideOfImportOrExportAssignment(node: EntityName) {
9154+
return getLeftSideOfImportOrExportAssignment(node) !== undefined;
91139155
}
91149156

91159157
function isRightSideOfQualifiedNameOrPropertyAccess(node: Node) {

src/compiler/types.ts

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

12271228
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)