Skip to content

Commit

Permalink
Rebase against master and clean up substitution flow
Browse files Browse the repository at this point in the history
  • Loading branch information
rbuckton committed Feb 9, 2021
1 parent 2d77419 commit 0bf051b
Show file tree
Hide file tree
Showing 84 changed files with 746 additions and 693 deletions.
151 changes: 102 additions & 49 deletions src/compiler/transformers/module/module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
/*@internal*/
namespace ts {

const enum ImportOrExportBindingReferenceKind {
None,
ImportedHelper,
TopLevelExportBinding,
ImportClause,
ImportSpecifier,
}

type ImportOrExportBindingReferenceResult =
| { kind: ImportOrExportBindingReferenceKind.None, node: undefined }
| { kind: ImportOrExportBindingReferenceKind.ImportedHelper, node: Identifier }
| { kind: ImportOrExportBindingReferenceKind.TopLevelExportBinding, node: undefined }
| { kind: ImportOrExportBindingReferenceKind.ImportClause, node: ImportClause }
| { kind: ImportOrExportBindingReferenceKind.ImportSpecifier, node: ImportSpecifier };

const noReferenceResult: ImportOrExportBindingReferenceResult = { kind: ImportOrExportBindingReferenceKind.None, node: undefined };
const topLevelExportReferenceResult: ImportOrExportBindingReferenceResult = { kind: ImportOrExportBindingReferenceKind.TopLevelExportBinding, node: undefined };

export function transformModule(context: TransformationContext) {
interface AsynchronousDependencies {
aliasedModuleNames: Expression[];
Expand Down Expand Up @@ -48,6 +67,7 @@ namespace ts {
let currentModuleInfo: ExternalModuleInfo; // The ExternalModuleInfo for the current file.
let noSubstitution: boolean[]; // Set of nodes for which substitution rules should be ignored.
let needUMDDynamicImportHelper: boolean;
let bindingReferenceCache: ESMap<Node, ImportOrExportBindingReferenceResult> | undefined;

return chainBundle(context, transformSourceFile);

Expand Down Expand Up @@ -1756,24 +1776,70 @@ namespace ts {
return node;
}

function substituteCallExpression(node: CallExpression) {
if (!isIdentifier(node.expression)) {
return node;
function getImportOrExportBindingReferenceWorker(node: Identifier): ImportOrExportBindingReferenceResult {
if (getEmitFlags(node) & EmitFlags.HelperName) {
const externalHelpersModuleName = getExternalHelpersModuleName(currentSourceFile);
if (externalHelpersModuleName) {
return { kind: ImportOrExportBindingReferenceKind.ImportedHelper, node: externalHelpersModuleName };
}
}
const newExpression = substituteExpressionIdentifier(node.expression);
if (newExpression !== node.expression) {
return updateCall(node, setTextRange(createBinary(createNumericLiteral("0"), SyntaxKind.CommaToken, newExpression), node.expression), /*typeArguments*/ undefined, node.arguments);
else if (!(isGeneratedIdentifier(node) && !(node.autoGenerateFlags & GeneratedIdentifierFlags.AllowNameSubstitution)) && !isLocalName(node)) {
const exportContainer = resolver.getReferencedExportContainer(node, isExportName(node));
if (exportContainer?.kind === SyntaxKind.SourceFile) {
return topLevelExportReferenceResult;
}
const importDeclaration = resolver.getReferencedImportDeclaration(node);
if (importDeclaration) {
if (isImportClause(importDeclaration)) return { kind: ImportOrExportBindingReferenceKind.ImportClause, node: importDeclaration };
if (isImportSpecifier(importDeclaration)) return { kind: ImportOrExportBindingReferenceKind.ImportSpecifier, node: importDeclaration };
}
}
return noReferenceResult;
}

function getImportOrExportBindingReference(node: Identifier, removeEntry: boolean): ImportOrExportBindingReferenceResult {
bindingReferenceCache ||= new Map();
let result = bindingReferenceCache.get(node);
if (!result) {
result = getImportOrExportBindingReferenceWorker(node);
if (!removeEntry) {
switch (result.kind) {
case ImportOrExportBindingReferenceKind.ImportedHelper:
case ImportOrExportBindingReferenceKind.ImportClause:
case ImportOrExportBindingReferenceKind.ImportSpecifier:
bindingReferenceCache.set(node, result);
}
}
}
else if (removeEntry) {
bindingReferenceCache.delete(node);
}
return result;
}

function substituteCallExpression(node: CallExpression) {
if (isIdentifier(node.expression) && getImportOrExportBindingReference(node.expression, /*removeEntry*/ false).kind !== ImportOrExportBindingReferenceKind.None) {
return isCallChain(node) ?
factory.updateCallChain(node,
setTextRange(factory.createComma(factory.createNumericLiteral(0), node.expression), node.expression),
node.questionDotToken,
/*typeArguments*/ undefined,
node.arguments) :
factory.updateCallExpression(node,
setTextRange(factory.createComma(factory.createNumericLiteral(0), node.expression), node.expression),
/*typeArguments*/ undefined,
node.arguments);
}
return node;
}

function substituteTaggedTemplateExpression(node: TaggedTemplateExpression) {
if (!isIdentifier(node.tag)) {
return node;
}
const newTag = substituteExpressionIdentifier(node.tag);
if (newTag !== node.tag) {
return updateTaggedTemplate(node, setTextRange(createBinary(createNumericLiteral("0"), SyntaxKind.CommaToken, newTag), node.tag), /*typeArguments*/ undefined, node.template);
if (isIdentifier(node.tag) && getImportOrExportBindingReference(node.tag, /*removeEntry*/ false).kind !== ImportOrExportBindingReferenceKind.None) {
return factory.updateTaggedTemplateExpression(
node,
setTextRange(factory.createComma(factory.createNumericLiteral(0), node.tag), node.tag),
/*typeArguments*/ undefined,
node.template);
}
return node;
}
Expand All @@ -1785,51 +1851,38 @@ namespace ts {
* @param node The node to substitute.
*/
function substituteExpressionIdentifier(node: Identifier): Expression {
if (getEmitFlags(node) & EmitFlags.HelperName) {
const externalHelpersModuleName = getExternalHelpersModuleName(currentSourceFile);
if (externalHelpersModuleName) {
return factory.createPropertyAccessExpression(externalHelpersModuleName, node);
}

return node;
}

if (!(isGeneratedIdentifier(node) && !(node.autoGenerateFlags & GeneratedIdentifierFlags.AllowNameSubstitution)) && !isLocalName(node)) {
const exportContainer = resolver.getReferencedExportContainer(node, isExportName(node));
if (exportContainer && exportContainer.kind === SyntaxKind.SourceFile) {
const result = getImportOrExportBindingReference(node, /*removeEntry*/ true);
switch (result.kind) {
case ImportOrExportBindingReferenceKind.ImportedHelper:
return factory.createPropertyAccessExpression(result.node, node);
case ImportOrExportBindingReferenceKind.TopLevelExportBinding:
return setTextRange(
factory.createPropertyAccessExpression(
factory.createIdentifier("exports"),
factory.cloneNode(node)
),
/*location*/ node
);
}

const importDeclaration = resolver.getReferencedImportDeclaration(node);
if (importDeclaration) {
if (isImportClause(importDeclaration)) {
return setTextRange(
factory.createPropertyAccessExpression(
factory.getGeneratedNameForNode(importDeclaration.parent),
factory.createIdentifier("default")
),
/*location*/ node
);
}
else if (isImportSpecifier(importDeclaration)) {
const name = importDeclaration.propertyName || importDeclaration.name;
return setTextRange(
factory.createPropertyAccessExpression(
factory.getGeneratedNameForNode(importDeclaration.parent?.parent?.parent || importDeclaration),
factory.cloneNode(name)
),
/*location*/ node
);
}
}
case ImportOrExportBindingReferenceKind.ImportClause:
return setTextRange(
factory.createPropertyAccessExpression(
factory.getGeneratedNameForNode(result.node.parent),
factory.createIdentifier("default")
),
/*location*/ node
);
case ImportOrExportBindingReferenceKind.ImportSpecifier:
const name = result.node.propertyName || result.node.name;
return setTextRange(
factory.createPropertyAccessExpression(
factory.getGeneratedNameForNode(result.node.parent?.parent?.parent || result.node),
factory.cloneNode(name)
),
/*location*/ node
);
default:
return node;
}
return node;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ var Component = /** @class */ (function () {
function Component() {
}
Component.prototype.render = function () {
return _a.jsx("div", { children: null /* preserved */ }, void 0);
return (0, _a.jsx)("div", { children: null /* preserved */ }, void 0);
};
return Component;
}());
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ var Component = /** @class */ (function () {
function Component() {
}
Component.prototype.render = function () {
return _a.jsxDEV("div", { children: null /* preserved */ }, void 0, false, { fileName: _jsxFileName, lineNumber: 5, columnNumber: 15 }, this);
return (0, _a.jsxDEV)("div", { children: null /* preserved */ }, void 0, false, { fileName: _jsxFileName, lineNumber: 5, columnNumber: 15 }, this);
};
return Component;
}());
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
//// [declarationEmitExpandoWithGenericConstraint.ts]
export interface Point {
readonly x: number;
readonly y: number;
}

export interface Rect<p extends Point> {
readonly a: p;
readonly b: p;
}

export const Point = (x: number, y: number): Point => ({ x, y });
export const Rect = <p extends Point>(a: p, b: p): Rect<p> => ({ a, b });

export interface Point {
readonly x: number;
readonly y: number;
}

export interface Rect<p extends Point> {
readonly a: p;
readonly b: p;
}

export const Point = (x: number, y: number): Point => ({ x, y });
export const Rect = <p extends Point>(a: p, b: p): Rect<p> => ({ a, b });

Point.zero = (): Point => Point(0, 0);

//// [declarationEmitExpandoWithGenericConstraint.js]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ var get_comp_1 = require("./get-comp");
// this shouldn't need any triple-slash references - it should have a direct import to `react` and that's it
// This issue (#35343) _only_ reproduces in the test harness when the file in question is in a subfolder
exports.obj = {
comp: get_comp_1.getComp()
comp: (0, get_comp_1.getComp)()
};
//// [some-other-file.js]
"use strict";
Expand Down
14 changes: 7 additions & 7 deletions tests/baselines/reference/declarationEmitExportDeclaration.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
//// [tests/cases/compiler/declarationEmitExportDeclaration.ts] ////

//// [utils.ts]
export function foo() { }
export function bar() { }
export interface Buzz { }
export function foo() { }
export function bar() { }
export interface Buzz { }

//// [index.ts]
import {foo, bar, Buzz} from "./utils";

foo();
let obj: Buzz;
import {foo, bar, Buzz} from "./utils";

foo();
let obj: Buzz;
export {bar};

//// [utils.js]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ var ParentThing = /** @class */ (function () {
return ParentThing;
}());
exports.ParentThing = ParentThing;
child1_1.child1(ParentThing.prototype);
(0, child1_1.child1)(ParentThing.prototype);
//// [child1.js]
"use strict";
exports.__esModule = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ var __assign = (this && this.__assign) || function () {
exports.__esModule = true;
exports.spread = void 0;
var bug_1 = require("./bug");
exports.spread = __assign({}, bug_1.createInstance());
exports.spread = __assign({}, (0, bug_1.createInstance)());


//// [bug.d.ts]
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/declarationEmitSymlinkPaths.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.NotificationScenario = void 0;
var index_1 = require("search/lib/index");
var NotificationAPIUtils_1 = require("../API/NotificationAPIUtils");
exports.NotificationScenario = index_1.test(NotificationAPIUtils_1.getNotification);
exports.NotificationScenario = (0, index_1.test)(NotificationAPIUtils_1.getNotification);


//// [NotificationAPIUtils.d.ts]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
//// [declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.ts]
// Note that both of the following have an `any` in their return type from where we bottom out the type printout
// for having too many instances of the same symbol nesting.

// Slightly simplified repro from https://github.com/microsoft/TypeScript/issues/30732 so it's easier to read and debug
export type Key<U> = keyof U;
export type Value<K extends Key<U>, U> = U[K];
export const updateIfChanged = <T>(t: T) => {
const reduce = <U>(u: U, update: (u: U) => T) => {
const set = (newU: U) => Object.is(u, newU) ? t : update(newU);
return Object.assign(
<K extends Key<U>>(key: K) =>
reduce<Value<K, U>>(u[key as keyof U] as Value<K, U>, (v: Value<K, U>) => {
return update(Object.assign(Array.isArray(u) ? [] : {}, u, { [key]: v }));
}),
{ map: (updater: (u: U) => U) => set(updater(u)), set });
};
return reduce<T>(t, (t: T) => t);
};

// example from https://github.com/microsoft/TypeScript/issues/31605

export const testRecFun = <T extends Object>(parent: T) => {
return {
result: parent,
deeper: <U extends Object>(child: U) =>
testRecFun<T & U>({ ...parent, ...child })
};
}


let p1 = testRecFun({ one: '1' })
void p1.result.one;
let p2 = p1.deeper({ two: '2' })
void p2.result.one;
void p2.result.two;
let p3 = p2.deeper({ three: '3' })
void p3.result.one;
void p3.result.two;
void p3.result.three;
// Note that both of the following have an `any` in their return type from where we bottom out the type printout
// for having too many instances of the same symbol nesting.

// Slightly simplified repro from https://github.com/microsoft/TypeScript/issues/30732 so it's easier to read and debug
export type Key<U> = keyof U;
export type Value<K extends Key<U>, U> = U[K];
export const updateIfChanged = <T>(t: T) => {
const reduce = <U>(u: U, update: (u: U) => T) => {
const set = (newU: U) => Object.is(u, newU) ? t : update(newU);
return Object.assign(
<K extends Key<U>>(key: K) =>
reduce<Value<K, U>>(u[key as keyof U] as Value<K, U>, (v: Value<K, U>) => {
return update(Object.assign(Array.isArray(u) ? [] : {}, u, { [key]: v }));
}),
{ map: (updater: (u: U) => U) => set(updater(u)), set });
};
return reduce<T>(t, (t: T) => t);
};

// example from https://github.com/microsoft/TypeScript/issues/31605

export const testRecFun = <T extends Object>(parent: T) => {
return {
result: parent,
deeper: <U extends Object>(child: U) =>
testRecFun<T & U>({ ...parent, ...child })
};
}


let p1 = testRecFun({ one: '1' })
void p1.result.one;
let p2 = p1.deeper({ two: '2' })
void p2.result.one;
void p2.result.two;
let p3 = p2.deeper({ three: '3' })
void p3.result.one;
void p3.result.two;
void p3.result.three;


//// [declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.js]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ exports.__esModule = true;
exports.__esModule = true;
exports.ns = void 0;
var tslib_1 = require("tslib");
exports.ns = tslib_1.__importStar(require("./a")); // Error
exports.ns = (0, tslib_1.__importStar)(require("./a")); // Error
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
Object.defineProperty(exports, "__esModule", { value: true });
// https://github.com/microsoft/TypeScript/issues/39149
const a_1 = __importDefault(require("a"));
a_1.default();
(0, a_1.default)();
Loading

0 comments on commit 0bf051b

Please sign in to comment.