Merge pull request #15502 from Microsoft/portFixes5-1-2017

Port fixes from master
This commit is contained in:
Mohamed Hegazy
2017-05-01 11:09:36 -07:00
committed by GitHub
16 changed files with 382 additions and 24 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "typescript",
"author": "Microsoft Corp.",
"homepage": "http://typescriptlang.org/",
"version": "2.3.2",
"version": "2.3.3",
"license": "Apache-2.0",
"description": "TypeScript is a language for application scale JavaScript development",
"keywords": [
+1 -1
View File
@@ -3,7 +3,7 @@
namespace ts {
/** The version of the TypeScript compiler release */
export const version = "2.3.2";
export const version = "2.3.3";
}
/* @internal */
+22
View File
@@ -2937,6 +2937,28 @@ namespace ts {
);
}
/**
* Gets the internal name of a declaration. This is primarily used for declarations that can be
* referred to by name in the body of an ES5 class function body. An internal name will *never*
* be prefixed with an module or namespace export modifier like "exports." when emitted as an
* expression. An internal name will also *never* be renamed due to a collision with a block
* scoped variable.
*
* @param node The declaration.
* @param allowComments A value indicating whether comments may be emitted for the name.
* @param allowSourceMaps A value indicating whether source maps may be emitted for the name.
*/
export function getInternalName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean) {
return getName(node, allowComments, allowSourceMaps, EmitFlags.LocalName | EmitFlags.InternalName);
}
/**
* Gets whether an identifier should only be referred to by its internal name.
*/
export function isInternalName(node: Identifier) {
return (getEmitFlags(node) & EmitFlags.InternalName) !== 0;
}
/**
* Gets the local name of a declaration. This is primarily used for declarations that can be
* referred to by name in the declaration's immediate scope (classes, enums, namespaces). A
+48 -8
View File
@@ -813,7 +813,7 @@ namespace ts {
// Create a synthetic text range for the return statement.
const closingBraceLocation = createTokenRange(skipTrivia(currentText, node.members.end), SyntaxKind.CloseBraceToken);
const localName = getLocalName(node);
const localName = getInternalName(node);
// The following partially-emitted expression exists purely to align our sourcemap
// emit with the original emitter.
@@ -870,7 +870,7 @@ namespace ts {
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
getDeclarationName(node),
getInternalName(node),
/*typeParameters*/ undefined,
transformConstructorParameters(constructor, hasSynthesizedSuper),
/*type*/ undefined,
@@ -3180,7 +3180,20 @@ namespace ts {
const savedConvertedLoopState = convertedLoopState;
convertedLoopState = undefined;
const ancestorFacts = enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes);
const updated = visitEachChild(node, visitor, context);
let updated: AccessorDeclaration;
if (node.transformFlags & TransformFlags.ContainsCapturedLexicalThis) {
const parameters = visitParameterList(node.parameters, visitor, context);
const body = transformFunctionBody(node);
if (node.kind === SyntaxKind.GetAccessor) {
updated = updateGetAccessor(node, node.decorators, node.modifiers, node.name, parameters, node.type, body);
}
else {
updated = updateSetAccessor(node, node.decorators, node.modifiers, node.name, parameters, body);
}
}
else {
updated = visitEachChild(node, visitor, context);
}
exitSubtree(ancestorFacts, HierarchyFacts.PropagateNewTargetMask, HierarchyFacts.None);
convertedLoopState = savedConvertedLoopState;
return updated;
@@ -3712,7 +3725,7 @@ namespace ts {
function substituteIdentifier(node: Identifier) {
// Only substitute the identifier if we have enabled substitutions for block-scoped
// bindings.
if (enabledSubstitutions & ES2015SubstitutionFlags.BlockScopedBindings) {
if (enabledSubstitutions & ES2015SubstitutionFlags.BlockScopedBindings && !isInternalName(node)) {
const original = getParseTreeNode(node, isIdentifier);
if (original && isNameOfDeclarationWithCollidingName(original)) {
return setTextRange(getGeneratedNameForNode(original), node);
@@ -3765,9 +3778,9 @@ namespace ts {
* @param node An Identifier node.
*/
function substituteExpressionIdentifier(node: Identifier): Identifier {
if (enabledSubstitutions & ES2015SubstitutionFlags.BlockScopedBindings) {
if (enabledSubstitutions & ES2015SubstitutionFlags.BlockScopedBindings && !isInternalName(node)) {
const declaration = resolver.getReferencedDeclarationWithCollidingName(node);
if (declaration) {
if (declaration && !(isClassLike(declaration) && isPartOfClassBody(declaration, node))) {
return setTextRange(getGeneratedNameForNode(declaration.name), node);
}
}
@@ -3775,6 +3788,32 @@ namespace ts {
return node;
}
function isPartOfClassBody(declaration: ClassLikeDeclaration, node: Identifier) {
let currentNode = getParseTreeNode(node);
if (!currentNode || currentNode === declaration || currentNode.end <= declaration.pos || currentNode.pos >= declaration.end) {
// if the node has no correlation to a parse tree node, its definitely not
// part of the body.
// if the node is outside of the document range of the declaration, its
// definitely not part of the body.
return false;
}
const blockScope = getEnclosingBlockScopeContainer(declaration);
while (currentNode) {
if (currentNode === blockScope || currentNode === declaration) {
// if we are in the enclosing block scope of the declaration, we are definitely
// not inside the class body.
return false;
}
if (isClassElement(currentNode) && currentNode.parent === declaration) {
// we are in the class body, but we treat static fields as outside of the class body
return currentNode.kind !== SyntaxKind.PropertyDeclaration
|| (getModifierFlags(currentNode) & ModifierFlags.Static) === 0;
}
currentNode = currentNode.parent;
}
return false;
}
/**
* Substitutes `this` when contained within an arrow function.
*
@@ -3789,8 +3828,9 @@ namespace ts {
}
function getClassMemberPrefix(node: ClassExpression | ClassDeclaration, member: ClassElement) {
const expression = getLocalName(node);
return hasModifier(member, ModifierFlags.Static) ? expression : createPropertyAccess(expression, "prototype");
return hasModifier(member, ModifierFlags.Static)
? getInternalName(node)
: createPropertyAccess(getInternalName(node), "prototype");
}
function hasSynthesizedDefaultSuperCall(constructor: ConstructorDeclaration, hasExtendsClause: boolean) {
+9 -8
View File
@@ -3940,14 +3940,15 @@ namespace ts {
HelperName = 1 << 12,
ExportName = 1 << 13, // Ensure an export prefix is added for an identifier that points to an exported declaration with a local name (see SymbolFlags.ExportHasLocal).
LocalName = 1 << 14, // Ensure an export prefix is not added for an identifier that points to an exported declaration.
Indented = 1 << 15, // Adds an explicit extra indentation level for class and function bodies when printing (used to match old emitter).
NoIndentation = 1 << 16, // Do not indent the node.
AsyncFunctionBody = 1 << 17,
ReuseTempVariableScope = 1 << 18, // Reuse the existing temp variable scope during emit.
CustomPrologue = 1 << 19, // Treat the statement as if it were a prologue directive (NOTE: Prologue directives are *not* transformed).
NoHoisting = 1 << 20, // Do not hoist this declaration in --module system
HasEndOfDeclarationMarker = 1 << 21, // Declaration has an associated NotEmittedStatement to mark the end of the declaration
Iterator = 1 << 22, // The expression to a `yield*` should be treated as an Iterator when down-leveling, not an Iterable.
InternalName = 1 << 15, // The name is internal to an ES5 class body function.
Indented = 1 << 16, // Adds an explicit extra indentation level for class and function bodies when printing (used to match old emitter).
NoIndentation = 1 << 17, // Do not indent the node.
AsyncFunctionBody = 1 << 18,
ReuseTempVariableScope = 1 << 19, // Reuse the existing temp variable scope during emit.
CustomPrologue = 1 << 20, // Treat the statement as if it were a prologue directive (NOTE: Prologue directives are *not* transformed).
NoHoisting = 1 << 21, // Do not hoist this declaration in --module system
HasEndOfDeclarationMarker = 1 << 22, // Declaration has an associated NotEmittedStatement to mark the end of the declaration
Iterator = 1 << 23, // The expression to a `yield*` should be treated as an Iterator when down-leveling, not an Iterable.
}
export interface EmitHelper {
@@ -0,0 +1,71 @@
//// [classBlockScoping.ts]
function f(b: boolean) {
let Foo: any;
if (b) {
Foo = class Foo {
static y = new Foo();
static x() {
new Foo();
}
m() {
new Foo();
}
};
new Foo();
}
else {
class Foo {
static y = new Foo();
static x() {
new Foo();
}
m() {
new Foo();
}
}
new Foo();
}
}
//// [classBlockScoping.js]
function f(b) {
var Foo;
if (b) {
Foo = (_a = (function () {
function Foo() {
}
Foo.x = function () {
new Foo();
};
Foo.prototype.m = function () {
new Foo();
};
return Foo;
}()),
_a.y = new _a(),
_a);
new Foo();
}
else {
var Foo_1 = (function () {
function Foo() {
}
Foo.x = function () {
new Foo();
};
Foo.prototype.m = function () {
new Foo();
};
return Foo;
}());
Foo_1.y = new Foo_1();
new Foo_1();
}
var _a;
}
@@ -0,0 +1,64 @@
=== tests/cases/compiler/classBlockScoping.ts ===
function f(b: boolean) {
>f : Symbol(f, Decl(classBlockScoping.ts, 0, 0))
>b : Symbol(b, Decl(classBlockScoping.ts, 0, 11))
let Foo: any;
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 1, 5))
if (b) {
>b : Symbol(b, Decl(classBlockScoping.ts, 0, 11))
Foo = class Foo {
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 1, 5))
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 3, 9))
static y = new Foo();
>y : Symbol(Foo.y, Decl(classBlockScoping.ts, 3, 21))
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 3, 9))
static x() {
>x : Symbol(Foo.x, Decl(classBlockScoping.ts, 4, 27))
new Foo();
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 3, 9))
}
m() {
>m : Symbol(Foo.m, Decl(classBlockScoping.ts, 8, 7))
new Foo();
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 3, 9))
}
};
new Foo();
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 1, 5))
}
else {
class Foo {
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 17, 8))
static y = new Foo();
>y : Symbol(Foo.y, Decl(classBlockScoping.ts, 18, 15))
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 17, 8))
static x() {
>x : Symbol(Foo.x, Decl(classBlockScoping.ts, 19, 27))
new Foo();
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 17, 8))
}
m() {
>m : Symbol(Foo.m, Decl(classBlockScoping.ts, 23, 7))
new Foo();
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 17, 8))
}
}
new Foo();
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 17, 8))
}
}
@@ -0,0 +1,74 @@
=== tests/cases/compiler/classBlockScoping.ts ===
function f(b: boolean) {
>f : (b: boolean) => void
>b : boolean
let Foo: any;
>Foo : any
if (b) {
>b : boolean
Foo = class Foo {
>Foo = class Foo { static y = new Foo(); static x() { new Foo(); } m() { new Foo(); } } : typeof Foo
>Foo : any
>class Foo { static y = new Foo(); static x() { new Foo(); } m() { new Foo(); } } : typeof Foo
>Foo : typeof Foo
static y = new Foo();
>y : Foo
>new Foo() : Foo
>Foo : typeof Foo
static x() {
>x : () => void
new Foo();
>new Foo() : Foo
>Foo : typeof Foo
}
m() {
>m : () => void
new Foo();
>new Foo() : Foo
>Foo : typeof Foo
}
};
new Foo();
>new Foo() : any
>Foo : any
}
else {
class Foo {
>Foo : Foo
static y = new Foo();
>y : Foo
>new Foo() : Foo
>Foo : typeof Foo
static x() {
>x : () => void
new Foo();
>new Foo() : Foo
>Foo : typeof Foo
}
m() {
>m : () => void
new Foo();
>new Foo() : Foo
>Foo : typeof Foo
}
}
new Foo();
>new Foo() : Foo
>Foo : typeof Foo
}
}
@@ -15,8 +15,8 @@ var C = (function () {
}());
{
var C_1 = (function () {
function C_1() {
function C() {
}
return C_1;
return C;
}());
}
@@ -19,9 +19,9 @@ function f() {
var c1 = C;
{
var C_1 = (function () {
function C_1() {
function C() {
}
return C_1;
return C;
}());
var c2 = C_1;
}
@@ -0,0 +1,15 @@
//// [emitThisInObjectLiteralGetter.ts]
const example = {
get foo() {
return item => this.bar(item);
}
};
//// [emitThisInObjectLiteralGetter.js]
var example = {
get foo() {
var _this = this;
return function (item) { return _this.bar(item); };
}
};
@@ -0,0 +1,13 @@
=== tests/cases/compiler/emitThisInObjectLiteralGetter.ts ===
const example = {
>example : Symbol(example, Decl(emitThisInObjectLiteralGetter.ts, 0, 5))
get foo() {
>foo : Symbol(foo, Decl(emitThisInObjectLiteralGetter.ts, 0, 17))
return item => this.bar(item);
>item : Symbol(item, Decl(emitThisInObjectLiteralGetter.ts, 2, 14))
>item : Symbol(item, Decl(emitThisInObjectLiteralGetter.ts, 2, 14))
}
};
@@ -0,0 +1,19 @@
=== tests/cases/compiler/emitThisInObjectLiteralGetter.ts ===
const example = {
>example : { readonly foo: (item: any) => any; }
>{ get foo() { return item => this.bar(item); }} : { readonly foo: (item: any) => any; }
get foo() {
>foo : (item: any) => any
return item => this.bar(item);
>item => this.bar(item) : (item: any) => any
>item : any
>this.bar(item) : any
>this.bar : any
>this : any
>bar : any
>item : any
}
};
+2 -2
View File
@@ -206,9 +206,9 @@ function f3(b) {
}
else {
var A_1 = (function () {
function A_1() {
function A() {
}
return A_1;
return A;
}());
var c = [new A_1()];
c[0].x = E.B;
+33
View File
@@ -0,0 +1,33 @@
function f(b: boolean) {
let Foo: any;
if (b) {
Foo = class Foo {
static y = new Foo();
static x() {
new Foo();
}
m() {
new Foo();
}
};
new Foo();
}
else {
class Foo {
static y = new Foo();
static x() {
new Foo();
}
m() {
new Foo();
}
}
new Foo();
}
}
@@ -0,0 +1,6 @@
// @target: es5
const example = {
get foo() {
return item => this.bar(item);
}
};