Skip to content

Streamline destructuring #12250

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Nov 16, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Jakefile.js
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,7 @@ task("importDefinitelyTypedTests", [importDefinitelyTypedTestsJs], function () {

// Local target to build the compiler and services
var tscFile = path.join(builtLocalDirectory, compilerFilename);
compileFile(tscFile, compilerSources, [builtLocalDirectory, copyright].concat(compilerSources), [copyright], /*useBuiltCompiler:*/ false);
compileFile(tscFile, compilerSources, [builtLocalDirectory, copyright].concat(compilerSources), [copyright], /*useBuiltCompiler:*/ false, { noMapRoot: true });

var servicesFile = path.join(builtLocalDirectory, "typescriptServices.js");
var servicesFileInBrowserTest = path.join(builtLocalDirectory, "typescriptServicesInBrowserTest.js");
Expand Down
150 changes: 99 additions & 51 deletions src/compiler/binder.ts

Large diffs are not rendered by default.

10 changes: 4 additions & 6 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3030,7 +3030,7 @@ namespace ts {
}

function isComputedNonLiteralName(name: PropertyName): boolean {
return name.kind === SyntaxKind.ComputedPropertyName && !isStringOrNumericLiteral((<ComputedPropertyName>name).expression.kind);
return name.kind === SyntaxKind.ComputedPropertyName && !isStringOrNumericLiteral((<ComputedPropertyName>name).expression);
}

function getRestType(source: Type, properties: PropertyName[], symbol: Symbol): Type {
Expand Down Expand Up @@ -3081,7 +3081,7 @@ namespace ts {
}
const literalMembers: PropertyName[] = [];
for (const element of pattern.elements) {
if (element.kind !== SyntaxKind.OmittedExpression && !(element as BindingElement).dotDotDotToken) {
if (!(element as BindingElement).dotDotDotToken) {
literalMembers.push(element.propertyName || element.name as Identifier);
}
}
Expand Down Expand Up @@ -8927,7 +8927,7 @@ namespace ts {
return type;
}

function getTypeOfDestructuredProperty(type: Type, name: Identifier | LiteralExpression | ComputedPropertyName) {
function getTypeOfDestructuredProperty(type: Type, name: PropertyName) {
const text = getTextOfPropertyName(name);
return getTypeOfPropertyOfType(type, text) ||
isNumericLiteralName(text) && getIndexTypeOfType(type, IndexKind.Number) ||
Expand Down Expand Up @@ -14221,9 +14221,7 @@ namespace ts {
}
}
else if (property.kind === SyntaxKind.SpreadAssignment) {
if (property.expression.kind !== SyntaxKind.Identifier) {
error(property.expression, Diagnostics.An_object_rest_element_must_be_an_identifier);
}
checkReferenceExpression(property.expression, Diagnostics.The_target_of_an_object_rest_assignment_must_be_a_variable_or_a_property_access);
}
else {
error(property, Diagnostics.Property_assignment_expected);
Expand Down
7 changes: 7 additions & 0 deletions src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,13 @@ namespace ts {
}
}

export function appendProperty<T>(map: Map<T>, key: string | number, value: T): Map<T> {
if (key === undefined || value === undefined) return map;
if (map === undefined) map = createMap<T>();
map[key] = value;
return map;
}

export function assign<T1 extends MapLike<{}>, T2, T3>(t: T1, arg1: T2, arg2: T3): T1 & T2 & T3;
export function assign<T1 extends MapLike<{}>, T2>(t: T1, arg1: T2): T1 & T2;
export function assign<T1 extends MapLike<{}>>(t: T1, ...args: any[]): any;
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1991,7 +1991,7 @@
"category": "Error",
"code": 2700
},
"An object rest element must be an identifier.": {
"The target of an object rest assignment must be a variable or a property access.": {
"category": "Error",
"code": 2701
},
Expand Down
772 changes: 273 additions & 499 deletions src/compiler/factory.ts

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1168,7 +1168,7 @@ namespace ts {

function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName {
if (token() === SyntaxKind.StringLiteral || token() === SyntaxKind.NumericLiteral) {
return parseLiteralNode(/*internName*/ true);
return <StringLiteral | NumericLiteral>parseLiteralNode(/*internName*/ true);
}
if (allowComputedPropertyNames && token() === SyntaxKind.OpenBracketToken) {
return parseComputedPropertyName();
Expand Down Expand Up @@ -5514,7 +5514,7 @@ namespace ts {
node.flags |= NodeFlags.GlobalAugmentation;
}
else {
node.name = parseLiteralNode(/*internName*/ true);
node.name = <StringLiteral>parseLiteralNode(/*internName*/ true);
}

if (token() === SyntaxKind.OpenBraceToken) {
Expand Down
72 changes: 48 additions & 24 deletions src/compiler/transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,25 +154,29 @@ namespace ts {
* @param transforms An array of Transformers.
*/
export function transformFiles(resolver: EmitResolver, host: EmitHost, sourceFiles: SourceFile[], transformers: Transformer[]): TransformationResult {
const lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = [];
const lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = [];
const enabledSyntaxKindFeatures = new Array<SyntaxKindFeatureFlags>(SyntaxKind.Count);

let lexicalEnvironmentDisabled = false;

let lexicalEnvironmentStackOffset = 0;
let hoistedVariableDeclarations: VariableDeclaration[];
let hoistedFunctionDeclarations: FunctionDeclaration[];
let lexicalEnvironmentDisabled: boolean;
let lexicalEnvironmentVariableDeclarations: VariableDeclaration[];
let lexicalEnvironmentFunctionDeclarations: FunctionDeclaration[];
let lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = [];
let lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = [];
let lexicalEnvironmentSuspended = false;

// The transformation context is provided to each transformer as part of transformer
// initialization.
const context: TransformationContext = {
getCompilerOptions: () => host.getCompilerOptions(),
getEmitResolver: () => resolver,
getEmitHost: () => host,
hoistVariableDeclaration,
hoistFunctionDeclaration,
startLexicalEnvironment,
suspendLexicalEnvironment,
resumeLexicalEnvironment,
endLexicalEnvironment,
hoistVariableDeclaration,
hoistFunctionDeclaration,
onSubstituteNode: (_emitContext, node) => node,
enableSubstitution,
isSubstitutionEnabled,
Expand Down Expand Up @@ -285,11 +289,11 @@ namespace ts {
function hoistVariableDeclaration(name: Identifier): void {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot modify the lexical environment during the print phase.");
const decl = createVariableDeclaration(name);
if (!hoistedVariableDeclarations) {
hoistedVariableDeclarations = [decl];
if (!lexicalEnvironmentVariableDeclarations) {
lexicalEnvironmentVariableDeclarations = [decl];
}
else {
hoistedVariableDeclarations.push(decl);
lexicalEnvironmentVariableDeclarations.push(decl);
}
}

Expand All @@ -298,11 +302,11 @@ namespace ts {
*/
function hoistFunctionDeclaration(func: FunctionDeclaration): void {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot modify the lexical environment during the print phase.");
if (!hoistedFunctionDeclarations) {
hoistedFunctionDeclarations = [func];
if (!lexicalEnvironmentFunctionDeclarations) {
lexicalEnvironmentFunctionDeclarations = [func];
}
else {
hoistedFunctionDeclarations.push(func);
lexicalEnvironmentFunctionDeclarations.push(func);
}
}

Expand All @@ -312,16 +316,31 @@ namespace ts {
*/
function startLexicalEnvironment(): void {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot start a lexical environment during the print phase.");
Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended.");

// Save the current lexical environment. Rather than resizing the array we adjust the
// stack size variable. This allows us to reuse existing array slots we've
// already allocated between transformations to avoid allocation and GC overhead during
// transformation.
lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset] = hoistedVariableDeclarations;
lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset] = hoistedFunctionDeclarations;
lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentVariableDeclarations;
lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentFunctionDeclarations;
lexicalEnvironmentStackOffset++;
hoistedVariableDeclarations = undefined;
hoistedFunctionDeclarations = undefined;
lexicalEnvironmentVariableDeclarations = undefined;
lexicalEnvironmentFunctionDeclarations = undefined;
}

/** Suspends the current lexical environment, usually after visiting a parameter list. */
function suspendLexicalEnvironment(): void {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot suspend a lexical environment during the print phase.");
Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is already suspended.");
lexicalEnvironmentSuspended = true;
}

/** Resumes a suspended lexical environment, usually before visiting a function body. */
function resumeLexicalEnvironment(): void {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot resume a lexical environment during the print phase.");
Debug.assert(lexicalEnvironmentSuspended, "Lexical environment is not suspended suspended.");
lexicalEnvironmentSuspended = false;
}

/**
Expand All @@ -330,17 +349,18 @@ namespace ts {
*/
function endLexicalEnvironment(): Statement[] {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot end a lexical environment during the print phase.");
Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended.");

let statements: Statement[];
if (hoistedVariableDeclarations || hoistedFunctionDeclarations) {
if (hoistedFunctionDeclarations) {
statements = [...hoistedFunctionDeclarations];
if (lexicalEnvironmentVariableDeclarations || lexicalEnvironmentFunctionDeclarations) {
if (lexicalEnvironmentFunctionDeclarations) {
statements = [...lexicalEnvironmentFunctionDeclarations];
}

if (hoistedVariableDeclarations) {
if (lexicalEnvironmentVariableDeclarations) {
const statement = createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(hoistedVariableDeclarations)
createVariableDeclarationList(lexicalEnvironmentVariableDeclarations)
);

if (!statements) {
Expand All @@ -354,8 +374,12 @@ namespace ts {

// Restore the previous lexical environment.
lexicalEnvironmentStackOffset--;
hoistedVariableDeclarations = lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset];
hoistedFunctionDeclarations = lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset];
lexicalEnvironmentVariableDeclarations = lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset];
lexicalEnvironmentFunctionDeclarations = lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset];
if (lexicalEnvironmentStackOffset === 0) {
lexicalEnvironmentVariableDeclarationsStack = [];
lexicalEnvironmentFunctionDeclarationsStack = [];
}
return statements;
}
}
Expand Down
Loading