From 8babde0b9839fbd500a3089abd33754f478a05d2 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Fri, 11 Nov 2016 17:23:42 -0800 Subject: [PATCH 01/10] WIP Clean up destructuring --- src/compiler/core.ts | 7 + src/compiler/factory.ts | 14 +- src/compiler/transformers/destructuring.ts | 758 ++++++++++++++++++++- src/compiler/transformers/esnext.ts | 2 +- src/compiler/types.ts | 10 +- src/compiler/utilities.ts | 26 +- src/compiler/visitor.ts | 30 + 7 files changed, 814 insertions(+), 33 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 8175730159b..a21477a40d6 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -811,6 +811,13 @@ namespace ts { } } + export function appendProperty(map: Map, key: string | number, value: T): Map { + if (key === undefined || value === undefined) return map; + if (map === undefined) map = createMap(); + map[key] = value; + return map; + } + export function assign, T2, T3>(t: T1, arg1: T2, arg2: T3): T1 & T2 & T3; export function assign, T2>(t: T1, arg1: T2): T1 & T2; export function assign>(t: T1, ...args: any[]): any; diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index e9935668676..6674ffc7263 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -238,9 +238,9 @@ namespace ts { return node; } - export function updateParameter(node: ParameterDeclaration, decorators: Decorator[], modifiers: Modifier[], name: BindingName, type: TypeNode, initializer: Expression) { - if (node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.type !== type || node.initializer !== initializer) { - return updateNode(createParameter(decorators, modifiers, node.dotDotDotToken, name, node.questionToken, type, initializer, /*location*/ node, /*flags*/ node.flags), node); + export function updateParameter(node: ParameterDeclaration, decorators: Decorator[], modifiers: Modifier[], dotDotDotToken: DotDotDotToken, name: BindingName, type: TypeNode, initializer: Expression) { + if (node.decorators !== decorators || node.modifiers !== modifiers || node.dotDotDotToken !== dotDotDotToken || node.name !== name || node.type !== type || node.initializer !== initializer) { + return updateNode(createParameter(decorators, modifiers, dotDotDotToken, name, node.questionToken, type, initializer, /*location*/ node, /*flags*/ node.flags), node); } return node; @@ -378,9 +378,9 @@ namespace ts { return node; } - export function updateBindingElement(node: BindingElement, propertyName: PropertyName, name: BindingName, initializer: Expression) { - if (node.propertyName !== propertyName || node.name !== name || node.initializer !== initializer) { - return updateNode(createBindingElement(propertyName, node.dotDotDotToken, name, initializer, node), node); + export function updateBindingElement(node: BindingElement, dotDotDotToken: DotDotDotToken, propertyName: PropertyName, name: BindingName, initializer: Expression) { + if (node.propertyName !== propertyName || node.dotDotDotToken !== dotDotDotToken || node.name !== name || node.initializer !== initializer) { + return updateNode(createBindingElement(propertyName, dotDotDotToken, name, initializer, node), node); } return node; } @@ -1635,7 +1635,7 @@ namespace ts { // flag and setting a parent node. const react = createIdentifier(reactNamespace || "React"); react.flags &= ~NodeFlags.Synthesized; - // Set the parent that is in parse tree + // Set the parent that is in parse tree // this makes sure that parent chain is intact for checker to traverse complete scope tree react.parent = getParseTreeNode(parent); return react; diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index bba09710898..b0cb3f9d239 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -3,6 +3,18 @@ /*@internal*/ namespace ts { + type EffectiveBindingElement = VariableDeclaration | ParameterDeclaration | BindingElement | ObjectLiteralElementLike | Expression; + type EffectiveObjectBindingPattern = ObjectBindingPattern | ObjectLiteralExpression; + type EffectiveArrayBindingPattern = ArrayBindingPattern | ArrayLiteralExpression; + type EffectiveBindingPattern = EffectiveObjectBindingPattern | EffectiveArrayBindingPattern; + type EffectiveBindingTarget = EffectiveBindingPattern | Expression; + type EffectiveRestIndicator = DotDotDotToken | SpreadElement | SpreadAssignment; + + export const enum FlattenLevel { + All, + ObjectRestDestructuringOnly, + } + /** * Flattens a destructuring assignment expression. * @@ -40,7 +52,7 @@ namespace ts { // // The source map location for the assignment should point to the entire binary // expression. - value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment, visitor); + value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment, visitor); } else if (nodeIsSynthesized(node)) { // Generally, the source map location for a destructuring assignment is the root @@ -52,7 +64,7 @@ namespace ts { location = value; } - flattenDestructuring(node, value, location, emitAssignment, emitTempVariableAssignment, recordTempVariable, emitRestAssignment, transformRest, visitor); + flattenDestructuringOld(node, value, location, emitAssignment, emitTempVariableAssignment, recordTempVariable, emitRestAssignment, transformRest, visitor); if (needsValue) { expressions.push(value); @@ -98,7 +110,7 @@ namespace ts { transformRest?: boolean) { const declarations: VariableDeclaration[] = []; - flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, noop, emitRestAssignment, transformRest, visitor); + flattenDestructuringOld(node, value, node, emitAssignment, emitTempVariableAssignment, noop, emitRestAssignment, transformRest, visitor); return declarations; @@ -140,7 +152,7 @@ namespace ts { const declarations: VariableDeclaration[] = []; let pendingAssignments: Expression[]; - flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, recordTempVariable, emitRestAssignment, transformRest, visitor); + flattenDestructuringOld(node, value, node, emitAssignment, emitTempVariableAssignment, recordTempVariable, emitRestAssignment, transformRest, visitor); return declarations; @@ -201,7 +213,7 @@ namespace ts { const pendingAssignments: Expression[] = []; - flattenDestructuring(node, /*value*/ undefined, node, emitAssignment, emitTempVariableAssignment, noop, emitRestAssignment, /*transformRest*/ false, visitor); + flattenDestructuringOld(node, /*value*/ undefined, node, emitAssignment, emitTempVariableAssignment, noop, emitRestAssignment, /*transformRest*/ false, visitor); const expression = inlineExpressions(pendingAssignments); aggregateTransformFlags(expression); @@ -238,7 +250,7 @@ namespace ts { } } - function flattenDestructuring( + function flattenDestructuringOld( root: VariableDeclaration | ParameterDeclaration | BindingElement | BinaryExpression, value: Expression, location: TextRange, @@ -305,7 +317,7 @@ namespace ts { // For anything but a single element destructuring we need to generate a temporary // to ensure value is evaluated exactly once. // When doing so we want to hightlight the passed in source map node since thats the one needing this temp assignment - value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); + value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); } let bindingElements: ObjectLiteralElementLike[] = []; @@ -361,7 +373,7 @@ namespace ts { // For anything but a single element destructuring we need to generate a temporary // to ensure value is evaluated exactly once. // When doing so we want to highlight the passed-in source map node since thats the one needing this temp assignment - value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); + value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); } const expressions: Expression[] = []; @@ -393,7 +405,7 @@ namespace ts { // For anything but a single element destructuring we need to generate a temporary // to ensure value is evaluated exactly once. // When doing so we want to highlight the passed-in source map node since thats the one needing this temp assignment - value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); + value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); } for (let i = 0; i < numElements; i++) { @@ -454,7 +466,7 @@ namespace ts { // to ensure value is evaluated exactly once. Additionally, if we have zero elements // we need to emit *something* to ensure that in case a 'var' keyword was already emitted, // so in that case, we'll intentionally create that temporary. - value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ numElements !== 0, target, emitTempVariableAssignment); + value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ numElements !== 0, target, emitTempVariableAssignment); } if (name.kind === SyntaxKind.ArrayBindingPattern) { emitArrayBindingElement(name as ArrayBindingPattern, value); @@ -558,7 +570,7 @@ namespace ts { } function createDefaultValueCheck(value: Expression, defaultValue: Expression, location: TextRange): Expression { - value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); + value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); return createConditional( createStrictEquality(value, createVoidZero()), createToken(SyntaxKind.QuestionToken), @@ -579,7 +591,7 @@ namespace ts { if (isComputedPropertyName(propertyName)) { return createElementAccess( expression, - ensureIdentifier(propertyName.expression, /*reuseIdentifierExpressions*/ false, /*location*/ propertyName, emitTempVariableAssignment) + ensureIdentifierOld(propertyName.expression, /*reuseIdentifierExpressions*/ false, /*location*/ propertyName, emitTempVariableAssignment) ); } else if (isLiteralExpression(propertyName)) { @@ -612,7 +624,7 @@ namespace ts { * @param emitTempVariableAssignment A callback used to emit a temporary variable. * @param visitor An optional callback used to visit the value. */ - function ensureIdentifier( + function ensureIdentifierOld( value: Expression, reuseIdentifierExpressions: boolean, location: TextRange, @@ -630,4 +642,724 @@ namespace ts { return emitTempVariableAssignment(value, location); } } + + interface FlattenHost { + context: TransformationContext; + level: FlattenLevel; + recordTempVariablesInLine: boolean; + emitAssignment: (target: EffectiveBindingTarget, value: Expression, location: TextRange, original: Node) => void; + emitArrayAssignment: (elements: EffectiveBindingElement[], value: Expression, location: TextRange, original: Node) => void; + emitObjectAssignment: (elements: EffectiveBindingElement[], value: Expression, location: TextRange, original: Node) => void; + emitExpression: (value: Expression) => void; + } + + export function flattenDestructuringToDeclarations( + context: TransformationContext, + node: VariableDeclaration | ParameterDeclaration, + boundValue: Expression | undefined, + recordTempVariablesInLine: boolean, + level: FlattenLevel): VisitResult { + + const pendingDeclarations: { pendingExpressions?: Expression[], name: BindingName, value: Expression, location?: TextRange, original?: Node; }[] = []; + let pendingExpressions: Expression[]; + let declaration: VariableDeclaration; + let declarations: VariableDeclaration[]; + const host: FlattenHost = { + context, + level, + recordTempVariablesInLine, + emitExpression, + emitAssignment, + emitArrayAssignment, + emitObjectAssignment + }; + + flattenEffectiveBindingElement(host, node, boundValue, node); + + if (pendingExpressions) { + const temp = createTempVariable(/*recordTempVariable*/ undefined); + if (recordTempVariablesInLine) { + const value = inlineExpressions(pendingExpressions); + pendingExpressions = undefined; + emitAssignment(temp, value, /*location*/ undefined, /*original*/ undefined); + } + else { + context.hoistVariableDeclaration(temp); + const pendingDeclaration = lastOrUndefined(pendingDeclarations); + pendingDeclaration.pendingExpressions = append( + pendingDeclaration.pendingExpressions, + createAssignment(temp, pendingDeclaration.value) + ); + addRange(pendingDeclaration.pendingExpressions, pendingExpressions); + pendingDeclaration.value = temp; + } + } + + for (const { pendingExpressions, name, value, location, original } of pendingDeclarations) { + const variable = createVariableDeclaration( + name, + /*type*/ undefined, + pendingExpressions ? inlineExpressions(append(pendingExpressions, value)) : value, + location); + variable.original = original; + if (isIdentifier(name)) { + setEmitFlags(variable, EmitFlags.NoNestedSourceMaps); + } + aggregateTransformFlags(variable); + if (!declaration) { + declaration = variable; + } + else if (!declarations) { + declarations = [declaration, variable]; + } + else { + declarations.push(variable); + } + } + + return declarations || declaration; + + function emitExpression(value: Expression) { + pendingExpressions = append(pendingExpressions, value); + } + + function emitAssignment(target: EffectiveBindingTarget, value: Expression, location: TextRange, original: Node) { + Debug.assertNode(target, isBindingName); + pendingDeclarations.push({ pendingExpressions, name: target, value, location, original }); + if (pendingExpressions) { + value = inlineExpressions(append(pendingExpressions, value)); + pendingExpressions = undefined; + } + } + + function emitArrayAssignment(elements: EffectiveBindingElement[], value: Expression, location: TextRange, original: Node) { + Debug.assertEachNode(elements, isArrayBindingElement); + emitAssignment(createArrayBindingPattern(elements), value, location, original); + } + + function emitObjectAssignment(elements: EffectiveBindingElement[], value: Expression, location: TextRange, original: Node) { + Debug.assertEachNode(elements, isBindingElement); + emitAssignment(createObjectBindingPattern(elements), value, location, original); + } + } + + function flattenEffectiveBindingElement( + host: FlattenHost, + bindingElement: EffectiveBindingElement, + boundValue: Expression | undefined, + location: TextRange, + skipInitializer?: boolean) { + if (!skipInitializer) { + const initializer = getInitializerOfEffectiveBindingElement(bindingElement); + if (initializer) { + // Combine value and initializer + boundValue = boundValue ? createDefaultValueCheck(host, boundValue, initializer, location) : initializer; + } + else if (!boundValue) { + // Use 'void 0' in absence of value and initializer + boundValue = createVoidZero(); + } + } + const bindingTarget = getTargetOfEffectiveBindingElement(bindingElement); + if (!isEffectiveBindingPattern(bindingTarget)) { + host.emitAssignment(bindingTarget, boundValue, location, /*original*/ bindingElement); + } + else { + const elements = getElementsOfEffectiveBindingPattern(bindingTarget); + const numElements = elements.length; + if (numElements !== 1) { + // For anything other than a single-element destructuring we need to generate a temporary + // to ensure value is evaluated exactly once. Additionally, if we have zero elements + // we need to emit *something* to ensure that in case a 'var' keyword was already emitted, + // so in that case, we'll intentionally create that temporary. + const reuseIdentifierExpressions = !isDeclarationBindingElement(bindingElement) || numElements !== 0; + boundValue = ensureIdentifier(host, boundValue, reuseIdentifierExpressions, location); + } + if (isEffectiveObjectBindingPattern(bindingTarget)) { + flattenEffectiveObjectBindingElements(host, bindingTarget, elements, boundValue, location); + } + else { + flattenEffectiveArrayBindingElements(host, bindingTarget, elements, boundValue, location); + } + } + } + + function flattenEffectiveObjectBindingElements(host: FlattenHost, bindingTarget: EffectiveObjectBindingPattern, elements: EffectiveBindingElement[], boundValue: Expression, location: TextRange) { + let bindingElements: EffectiveBindingElement[]; + const numElements = elements.length; + for (let i = 0; i < numElements; i++) { + const element = elements[i]; + if (!getEffectiveRestIndicator(element)) { + if (host.level >= FlattenLevel.ObjectRestDestructuringOnly && !(element.transformFlags & TransformFlags.ContainsSpreadExpression)) { + bindingElements = append(bindingElements, element); + } + else { + if (bindingElements) { + host.emitObjectAssignment(bindingElements, boundValue, location, bindingTarget); + bindingElements = undefined; + } + const propertyName = getEffectivePropertyNameOfEffectiveBindingElement(element); + const value = createDestructuringPropertyAccess(host, boundValue, propertyName); + flattenEffectiveBindingElement(host, element, value, /*location*/ element); + } + } + else if (i === numElements - 1) { + if (bindingElements) { + host.emitObjectAssignment(bindingElements, boundValue, location, bindingTarget); + bindingElements = undefined; + } + const value = createRestCall(boundValue, elements, bindingTarget); + flattenEffectiveBindingElement(host, element, value, element); + } + } + if (bindingElements) { + host.emitObjectAssignment(bindingElements, boundValue, location, bindingTarget); + } + } + + function flattenEffectiveArrayBindingElements(host: FlattenHost, bindingTarget: EffectiveArrayBindingPattern, elements: EffectiveBindingElement[], boundValue: Expression, location: TextRange) { + let bindingElements: EffectiveBindingElement[]; + let spreadContainingElements: EffectiveBindingElement[]; + let tempNames: Map; + const numElements = elements.length; + for (let i = 0; i < numElements; i++) { + const element = elements[i]; + if (isOmittedExpression(element)) { + continue; + } + else if (host.level >= FlattenLevel.ObjectRestDestructuringOnly) { + if (element.transformFlags & TransformFlags.ContainsSpreadExpression) { + const temp = createTempVariable(/*recordTempVariable*/ undefined); + tempNames = appendProperty(tempNames, getNodeId(element), temp); + spreadContainingElements = append(spreadContainingElements, element); + bindingElements = append(bindingElements, temp); + } + else { + bindingElements = append(bindingElements, element); + } + } + else if (!getEffectiveRestIndicator(element)) { + const value = createElementAccess(boundValue, i); + flattenEffectiveBindingElement(host, element, value, /*location*/ element); + } + else if (i === numElements - 1) { + const value = createArraySlice(boundValue, i); + flattenEffectiveBindingElement(host, element, value, /*location*/ element); + } + } + if (bindingElements) { + host.emitArrayAssignment(bindingElements, boundValue, location, bindingTarget); + } + if (spreadContainingElements) { + for (const element of spreadContainingElements) { + flattenEffectiveBindingElement(host, element, tempNames[getNodeId(element)], element); + } + } + } + + /** + * Creates an expression used to provide a default value if a value is `undefined` at runtime. + */ + function createDefaultValueCheck(host: FlattenHost, value: Expression, defaultValue: Expression, location: TextRange): Expression { + value = ensureIdentifier(host, value, /*reuseIdentifierExpressions*/ true, location); + return createConditional( + createStrictEquality(value, createVoidZero()), + createToken(SyntaxKind.QuestionToken), + defaultValue, + createToken(SyntaxKind.ColonToken), + value + ); + } + + /** + * Creates either a PropertyAccessExpression or an ElementAccessExpression for the + * right-hand side of a transformed destructuring assignment. + * + * @param expression The right-hand expression that is the source of the property. + * @param propertyName The destructuring property name. + * @param emitTempVariableAssignment A callback used to emit a temporary variable. + */ + function createDestructuringPropertyAccess(host: FlattenHost, expression: Expression, propertyName: PropertyName): LeftHandSideExpression { + if (isComputedPropertyName(propertyName)) { + const argumentExpression = ensureIdentifier(host, propertyName.expression, /*reuseIdentifierExpressions*/ false, /*location*/ propertyName); + return createElementAccess(expression, argumentExpression); + } + else if (isLiteralExpression(propertyName)) { + const argumentExpression = getSynthesizedClone(propertyName); + argumentExpression.text = unescapeIdentifier(argumentExpression.text); + return createElementAccess(expression, argumentExpression); + } + else if (isGeneratedIdentifier(propertyName)) { + const name = getSynthesizedClone(propertyName); + name.text = unescapeIdentifier(name.text); + return createPropertyAccess(expression, name); + } + else { + const name = createIdentifier(unescapeIdentifier(propertyName.text)); + return createPropertyAccess(expression, name); + } + } + + /** + * Ensures that there exists a declared identifier whose value holds the given expression. + * This function is useful to ensure that the expression's value can be read from in subsequent expressions. + * Unless 'reuseIdentifierExpressions' is false, 'value' will be returned if it is just an identifier. + * + * @param value the expression whose value needs to be bound. + * @param reuseIdentifierExpressions true if identifier expressions can simply be returned; + * false if it is necessary to always emit an identifier. + * @param emitTempVariableAssignment A callback used to emit a temporary variable. + * @param location The location to use for source maps and comments. + */ + function ensureIdentifier( + host: FlattenHost, + value: Expression, + reuseIdentifierExpressions: boolean, + location: TextRange) { + + if (isIdentifier(value) && reuseIdentifierExpressions) { + return value; + } + else { + const temp = createTempVariable(/*recordTempVariable*/ undefined); + if (host.recordTempVariablesInLine) { + host.emitAssignment(temp, value, location, /*original*/ undefined); + } + else { + host.context.hoistVariableDeclaration(temp); + host.emitExpression(createAssignment(temp, value, location)); + } + return temp; + } + } + + /** + * Determines whether the EffectiveBindingElement is a declaration + */ + function isDeclarationBindingElement(bindingElement: EffectiveBindingElement): bindingElement is VariableDeclaration | ParameterDeclaration | BindingElement { + switch (bindingElement.kind) { + case SyntaxKind.VariableDeclaration: + case SyntaxKind.Parameter: + case SyntaxKind.BindingElement: + return true; + } + + return false; + } + + /** + * Gets the initializer of an EffectiveBindingElement. + */ + function getInitializerOfEffectiveBindingElement(bindingElement: EffectiveBindingElement): Expression | undefined { + if (isDeclarationBindingElement(bindingElement)) { + // `1` in `let { a = 1 } = ...` + // `1` in `let { a: b = 1 } = ...` + // `1` in `let { a: {b} = 1 } = ...` + // `1` in `let { a: [b] = 1 } = ...` + // `1` in `let [a = 1] = ...` + // `1` in `let [{a} = 1] = ...` + // `1` in `let [[a] = 1] = ...` + return bindingElement.initializer; + } + + if (isPropertyAssignment(bindingElement)) { + // `1` in `({ a: b = 1 } = ...)` + // `1` in `({ a: {b} = 1 } = ...)` + // `1` in `({ a: [b] = 1 } = ...)` + return isAssignmentExpression(bindingElement.initializer, /*excludeCompoundAssignment*/ true) + ? bindingElement.initializer.right + : undefined; + } + + if (isShorthandPropertyAssignment(bindingElement)) { + // `1` in `({ a = 1 } = ...)` + return bindingElement.objectAssignmentInitializer; + } + + if (isAssignmentExpression(bindingElement, /*excludeCompoundAssignment*/ true)) { + // `1` in `[a = 1] = ...` + // `1` in `[{a} = 1] = ...` + // `1` in `[[a] = 1] = ...` + return bindingElement.right; + } + + if (isSpreadExpression(bindingElement) || isPartiallyEmittedExpression(bindingElement)) { + // Recovery consistent with existing emit. + return getInitializerOfEffectiveBindingElement(bindingElement.expression); + } + } + + /** + * Gets the name of an EffectiveBindingElement. + */ + function getTargetOfEffectiveBindingElement(bindingElement: EffectiveBindingElement): EffectiveBindingTarget { + if (isDeclarationBindingElement(bindingElement)) { + // `a` in `let { a } = ...` + // `a` in `let { a = 1 } = ...` + // `b` in `let { a: b } = ...` + // `b` in `let { a: b = 1 } = ...` + // `a` in `let { ...a } = ...` + // `{b}` in `let { a: {b} } = ...` + // `{b}` in `let { a: {b} = 1 } = ...` + // `[b]` in `let { a: [b] } = ...` + // `[b]` in `let { a: [b] = 1 } = ...` + // `a` in `let [a] = ...` + // `a` in `let [a = 1] = ...` + // `a` in `let [...a] = ...` + // `{a}` in `let [{a}] = ...` + // `{a}` in `let [{a} = 1] = ...` + // `[a]` in `let [[a]] = ...` + // `[a]` in `let [[a] = 1] = ...` + return bindingElement.name; + } + + if (isObjectLiteralElementLike(bindingElement)) { + switch (bindingElement.kind) { + case SyntaxKind.PropertyAssignment: + // `b` in `({ a: b } = ...)` + // `b` in `({ a: b = 1 } = ...)` + // `{b}` in `({ a: {b} } = ...)` + // `{b}` in `({ a: {b} = 1 } = ...)` + // `[b]` in `({ a: [b] } = ...)` + // `[b]` in `({ a: [b] = 1 } = ...)` + // `b.c` in `({ a: b.c } = ...)` + // `b.c` in `({ a: b.c = 1 } = ...)` + // `b[0]` in `({ a: b[0] } = ...)` + // `b[0]` in `({ a: b[0] = 1 } = ...)` + return getTargetOfEffectiveBindingElement(bindingElement.initializer); + + case SyntaxKind.ShorthandPropertyAssignment: + // `a` in `({ a } = ...)` + // `a` in `({ a = 1 } = ...)` + return bindingElement.name; + + case SyntaxKind.SpreadAssignment: + // `a` in `({ ...a } = ...)` + return getTargetOfEffectiveBindingElement(bindingElement.expression); + } + + // no target + return undefined; + } + + if (isAssignmentExpression(bindingElement, /*excludeCompoundAssignment*/ true)) { + // `a` in `[a = 1] = ...` + // `{a}` in `[{a} = 1] = ...` + // `[a]` in `[[a] = 1] = ...` + // `a.b` in `[a.b = 1] = ...` + // `a[0]` in `[a[0] = 1] = ...` + return getTargetOfEffectiveBindingElement(bindingElement.left); + } + + if (isSpreadExpression(bindingElement) || isPartiallyEmittedExpression(bindingElement)) { + // `a` in `[...a] = ...` + return getTargetOfEffectiveBindingElement(bindingElement.expression); + } + + // `a` in `[a] = ...` + // `{a}` in `[{a}] = ...` + // `[a]` in `[[a]] = ...` + // `a.b` in `[a.b] = ...` + // `a[0]` in `[a[0]] = ...` + return bindingElement; + } + + /** + * Determines whether an EffectiveBindingElement is a rest element. + */ + function getEffectiveRestIndicator(bindingElement: EffectiveBindingElement): EffectiveRestIndicator { + switch (bindingElement.kind) { + case SyntaxKind.Parameter: + case SyntaxKind.BindingElement: + // `...` in `let [...a] = ...` + return (bindingElement).dotDotDotToken; + + case SyntaxKind.SpreadElement: + case SyntaxKind.SpreadAssignment: + // `...` in `[...a] = ...` + return bindingElement; + } + + return undefined; + } + + /** + * Gets the property name of a BindingElement-like element + */ + function getEffectivePropertyNameOfEffectiveBindingElement(bindingElement: EffectiveBindingElement) { + switch (bindingElement.kind) { + case SyntaxKind.BindingElement: + // `a` in `let { a: b } = ...` + // `[a]` in `let { [a]: b } = ...` + // `"a"` in `let { "a": b } = ...` + // `1` in `let { 1: b } = ...` + if ((bindingElement).propertyName) { + return (bindingElement).propertyName; + } + + break; + + case SyntaxKind.PropertyAssignment: + // `a` in `({ a: b } = ...)` + // `[a]` in `({ [a]: b } = ...)` + // `"a"` in `({ "a": b } = ...)` + // `1` in `({ 1: b } = ...)` + if ((bindingElement).name) { + return (bindingElement).name; + } + + break; + + case SyntaxKind.SpreadAssignment: + // `a` in `({ ...a } = ...)` + return (bindingElement).name; + } + + const target = getTargetOfEffectiveBindingElement(bindingElement); + if (target && isPropertyName(target)) { + return target; + } + + Debug.fail("Invalid property name for binding element."); + } + + /** + * Determines whether a node is BindingPattern-like + */ + function isEffectiveBindingPattern(node: EffectiveBindingTarget): node is EffectiveBindingPattern { + return isEffectiveObjectBindingPattern(node) + || isEffectiveArrayBindingPattern(node); + } + + /** + * Determines whether a node is ObjectBindingPattern-like + */ + function isEffectiveObjectBindingPattern(node: EffectiveBindingTarget): node is EffectiveObjectBindingPattern { + switch (node.kind) { + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ObjectLiteralExpression: + return true; + } + + return false; + } + + /** + * Determines whether a node is ArrayBindingPattern-like + */ + function isEffectiveArrayBindingPattern(node: EffectiveBindingTarget): node is EffectiveArrayBindingPattern { + switch (node.kind) { + case SyntaxKind.ArrayBindingPattern: + case SyntaxKind.ArrayLiteralExpression: + return true; + } + + return false; + } + + /** + * Gets the elements of a BindingPattern-like name + */ + function getElementsOfEffectiveBindingPattern(name: EffectiveBindingPattern): EffectiveBindingElement[] { + switch (name.kind) { + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: + case SyntaxKind.ArrayLiteralExpression: + // `a` in `{a}` + // `a` in `[a]` + return name.elements; + + case SyntaxKind.ObjectLiteralExpression: + // `a` in `{a}` + return name.properties; + } + } + + // function updateEffectiveBindingElement(bindingElement: EffectiveBindingElement, restIndicator: EffectiveRestIndicator, propertyName: PropertyName, target: EffectiveBindingTarget, initializer: Expression) { + // switch (bindingElement.kind) { + // case SyntaxKind.VariableDeclaration: + // Debug.assertNode(target, isBindingName); + // Debug.assertMissingNode(propertyName); + // return updateVariableDeclaration( + // bindingElement, + // target, + // /*type*/ undefined, + // initializer + // ); + + // case SyntaxKind.Parameter: + // Debug.assertOptionalToken(restIndicator, SyntaxKind.DotDotDotToken); + // Debug.assertMissingNode(propertyName); + // Debug.assertNode(target, isBindingName); + // return updateParameter( + // bindingElement, + // /*decorators*/ undefined, + // /*modifiers*/ undefined, + // restIndicator, + // target, + // /*type*/ undefined, + // initializer + // ); + + // case SyntaxKind.BindingElement: + // Debug.assertOptionalToken(restIndicator, SyntaxKind.DotDotDotToken); + // Debug.assertNode(target, isBindingName); + // return updateBindingElement( + // bindingElement, + // restIndicator, + // propertyName, + // target, + // initializer + // ); + + // case SyntaxKind.PropertyAssignment: + // case SyntaxKind.ShorthandPropertyAssignment: + // case SyntaxKind.SpreadAssignment: + // if (restIndicator) { + // return convertToSpreadAssignment(bindingElement, propertyName, target, initializer); + // } + // else if (propertyName) { + // return convertToPropertyAssignment(bindingElement, propertyName, target, initializer); + // } + // else { + // return convertToShorthandPropertyAssignment(bindingElement, target, initializer); + // } + + // case SyntaxKind.ArrayLiteralExpression: + // case SyntaxKind.BinaryExpression: + // case SyntaxKind.SpreadElement: + // case SyntaxKind.PropertyAccessExpression: + // case SyntaxKind.ElementAccessExpression: + // Debug.assertMissingNode(propertyName); + // if (restIndicator) { + // return convertToSpreadElement(bindingElement, target, initializer); + // } + // else { + + // } + // } + // } + + // function convertToSpreadAssignment(node: PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment, propertyName: PropertyName, target: EffectiveBindingTarget, initializer: Expression) { + // Debug.assertMissingNode(propertyName); + // Debug.assertNode(target, isIdentifier); + // Debug.assertMissingNode(initializer); + // if (node.kind === SyntaxKind.SpreadAssignment) { + // return updateSpreadAssignment(node, target); + // } + // return setOriginalNode( + // createSpreadAssignment( + // target, + // node + // ), + // node + // ); + // } + + // function convertToPropertyAssignment(node: PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment, propertyName: PropertyName, target: EffectiveBindingTarget, initializer: Expression) { + // Debug.assertNode(target, isExpression); + // if (node.kind === SyntaxKind.PropertyAssignment) { + // return updatePropertyAssignment( + // node, + // propertyName, + // initializer ? + // isAssignmentExpression(node.initializer, /*excludeCompoundAssignment*/ true) + // ? updateBinary(node.initializer, target, initializer) + // : createAssignment(target, initializer) + // : target + // ); + // } + // return setOriginalNode( + // createPropertyAssignment( + // propertyName, + // initializer ? + // createAssignment(target, initializer) + // : target, + // node + // ), + // node + // ); + // } + + // function convertToShorthandPropertyAssignment(node: PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment, target: EffectiveBindingTarget, initializer: Expression) { + // Debug.assertNode(target, isIdentifier); + // if (node.kind === SyntaxKind.ShorthandPropertyAssignment) { + // return updateShorthandPropertyAssignment( + // node, + // target, + // initializer + // ); + // } + // return setOriginalNode( + // createShorthandPropertyAssignment( + // target, + // initializer, + // node + // ), + // node + // ); + // } + + // function convertToSpreadElement(node: Expression, target: EffectiveBindingTarget, initializer: Expression) { + // Debug.assertNode(target, isExpression); + // Debug.assertMissingNode(initializer); + // if (node.kind === SyntaxKind.SpreadElement) { + // return updateSpread( + // node, + // target); + // } + // return setOriginalNode( + // createSpread( + // target, + // node + // ), + // node + // ); + // } + + // function convertToElement(node: Expression, target: EffectiveBindingTarget, initializer: Expression) { + + // } + + function createOrUpdateVariableDeclaration(node: Node, name: BindingName, initializer: Expression, location: TextRange) { + if (node && node.kind === SyntaxKind.VariableDeclaration) { + return updateVariableDeclaration(node, name, /*type*/ undefined, initializer); + } + const variable = createVariableDeclaration(name, /*type*/ undefined, initializer, location); + return node ? setOriginalNode(variable, node) : variable; + } + + function createOrUpdateArrayBindingPattern(node: Node, elements: ArrayBindingElement[], location: TextRange) { + if (node && node.kind === SyntaxKind.ArrayBindingPattern) { + return updateArrayBindingPattern(node, elements); + } + const pattern = createArrayBindingPattern(elements, location); + return node ? setOriginalNode(pattern, node) : pattern; + } + + function createOrUpdateObjectBindingPattern(node: Node, elements: BindingElement[], location: TextRange) { + if (node && node.kind === SyntaxKind.ArrayBindingPattern) { + return updateObjectBindingPattern(node, elements); + } + const pattern = createObjectBindingPattern(elements, location); + return node ? setOriginalNode(pattern, node) : pattern; + } + + /** Given value: o, propName: p, pattern: { a, b, ...p } from the original statement + * `{ a, b, ...p } = o`, create `p = __rest(o, ["a", "b"]);`*/ + function createRestCall(value: Expression, elements: EffectiveBindingElement[], location: TextRange): Expression { + const propertyNames: LiteralExpression[] = []; + for (let i = 0; i < elements.length - 1; i++) { + if (isOmittedExpression(elements[i])) { + continue; + } + const str = createSynthesizedNode(SyntaxKind.StringLiteral); + str.pos = location.pos; + str.end = location.end; + str.text = getTextOfPropertyName(getEffectivePropertyNameOfEffectiveBindingElement(elements[i])); + propertyNames.push(str); + } + const args = createSynthesizedNodeArray([value, createArrayLiteral(propertyNames, location)]); + return createCall(createIdentifier("__rest"), undefined, args); + } } diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 1fad209bdb3..9013fabf584 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -105,7 +105,7 @@ namespace ts { * @param node A BinaryExpression node. */ function visitBinaryExpression(node: BinaryExpression): Expression { - if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.AssertESNext) { + if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.ContainsESNext) { return flattenDestructuringAssignment(context, node, /*needsDestructuringValue*/ true, hoistVariableDeclaration, visitor, /*transformRest*/ true); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c814a2b1d46..e8018083783 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1175,16 +1175,18 @@ namespace ts { right: Expression; } - export interface AssignmentExpression extends BinaryExpression { + export type AssignmentOperatorToken = Token; + + export interface AssignmentExpression extends BinaryExpression { left: LeftHandSideExpression; - operatorToken: Token; + operatorToken: TOperator; } - export interface ObjectDestructuringAssignment extends AssignmentExpression { + export interface ObjectDestructuringAssignment extends AssignmentExpression { left: ObjectLiteralExpression; } - export interface ArrayDestructuringAssignment extends AssignmentExpression { + export interface ArrayDestructuringAssignment extends AssignmentExpression { left: ArrayLiteralExpression; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index c49c33b857f..f0a666e1531 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3125,19 +3125,21 @@ namespace ts { } } - export function isAssignmentExpression(node: Node): node is AssignmentExpression { + export function isAssignmentExpression(node: Node, excludeCompoundAssignment: true): node is AssignmentExpression; + export function isAssignmentExpression(node: Node, excludeCompoundAssignment?: false): node is AssignmentExpression; + export function isAssignmentExpression(node: Node, excludeCompoundAssignment?: boolean): node is AssignmentExpression { return isBinaryExpression(node) - && isAssignmentOperator(node.operatorToken.kind) + && (excludeCompoundAssignment + ? node.operatorToken.kind === SyntaxKind.EqualsToken + : isAssignmentOperator(node.operatorToken.kind)) && isLeftHandSideExpression(node.left); } export function isDestructuringAssignment(node: Node): node is DestructuringAssignment { - if (isBinaryExpression(node)) { - if (node.operatorToken.kind === SyntaxKind.EqualsToken) { - const kind = node.left.kind; - return kind === SyntaxKind.ObjectLiteralExpression - || kind === SyntaxKind.ArrayLiteralExpression; - } + if (isAssignmentExpression(node, /*excludeCompoundAssignment*/ true)) { + const kind = node.left.kind; + return kind === SyntaxKind.ObjectLiteralExpression + || kind === SyntaxKind.ArrayLiteralExpression; } return false; @@ -3918,6 +3920,14 @@ namespace ts { // Binding patterns + export function isArrayBindingPattern(node: Node): node is ArrayBindingPattern { + return node.kind === SyntaxKind.ArrayBindingPattern; + } + + export function isObjectBindingPattern(node: Node): node is ObjectBindingPattern { + return node.kind === SyntaxKind.ObjectBindingPattern; + } + export function isBindingPattern(node: Node): node is BindingPattern { if (node) { const kind = node.kind; diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index cc27d5c9ddf..ebb3ec01ed3 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -701,6 +701,7 @@ namespace ts { return updateParameter(node, visitNodes((node).decorators, visitor, isDecorator), visitNodes((node).modifiers, visitor, isModifier), + (node).dotDotDotToken, visitNode((node).name, visitor, isBindingName), visitNode((node).type, visitor, isTypeNode, /*optional*/ true), visitNode((node).initializer, visitor, isExpression, /*optional*/ true)); @@ -767,6 +768,7 @@ namespace ts { case SyntaxKind.BindingElement: return updateBindingElement(node, + (node).dotDotDotToken, visitNode((node).propertyName, visitor, isPropertyName, /*optional*/ true), visitNode((node).name, visitor, isBindingName), visitNode((node).initializer, visitor, isExpression, /*optional*/ true)); @@ -1287,6 +1289,13 @@ namespace ts { ? (node: Node, message?: string) => assert(false, message || "Unexpected node.", () => `Node ${formatSyntaxKind(node.kind)} was unexpected.`) : noop; + export const assertEachNode = shouldAssert(AssertionLevel.Normal) + ? (nodes: Node[], test: (node: Node) => boolean, message?: string) => assert( + test === undefined || every(nodes, test), + message || "Unexpected node.", + () => `Node array did not pass test '${getFunctionName(test)}'.`) + : noop; + export const assertNode = shouldAssert(AssertionLevel.Normal) ? (node: Node, test: (node: Node) => boolean, message?: string) => assert( test === undefined || test(node), @@ -1294,6 +1303,27 @@ namespace ts { () => `Node ${formatSyntaxKind(node.kind)} did not pass test '${getFunctionName(test)}'.`) : noop; + export const assertOptionalNode = shouldAssert(AssertionLevel.Normal) + ? (node: Node, test: (node: Node) => boolean, message?: string) => assert( + test === undefined || node === undefined || test(node), + message || "Unexpected node.", + () => `Node ${formatSyntaxKind(node.kind)} did not pass test '${getFunctionName(test)}'.`) + : noop; + + export const assertOptionalToken = shouldAssert(AssertionLevel.Normal) + ? (node: Node, kind: SyntaxKind, message?: string) => assert( + kind === undefined || node === undefined || node.kind === kind, + message || "Unexpected node.", + () => `Node ${formatSyntaxKind(node.kind)} was not a '${formatSyntaxKind(kind)}' token.`) + : noop; + + export const assertMissingNode = shouldAssert(AssertionLevel.Normal) + ? (node: Node, message?: string) => assert( + node === undefined, + message || "Unexpected node.", + () => `Node ${formatSyntaxKind(node.kind)} was unexpected'.`) + : noop; + function getFunctionName(func: Function) { if (typeof func !== "function") { return ""; From d5b9263433c7e6b77eee0b138005333eebc00058 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 14 Nov 2016 10:40:26 -0800 Subject: [PATCH 02/10] Consolidate destructuring code paths --- src/compiler/binder.ts | 114 +- src/compiler/factory.ts | 47 +- src/compiler/transformers/destructuring.ts | 1157 ++++------------- src/compiler/transformers/es2015.ts | 63 +- src/compiler/transformers/es2017.ts | 154 +-- src/compiler/transformers/esnext.ts | 60 +- src/compiler/transformers/jsx.ts | 8 +- src/compiler/transformers/module/module.ts | 12 +- src/compiler/transformers/module/system.ts | 10 +- src/compiler/transformers/ts.ts | 6 +- src/compiler/types.ts | 81 +- src/compiler/visitor.ts | 447 ++++--- .../reference/assignmentTypeNarrowing.js | 10 +- .../reference/asyncMethodWithSuper_es5.js | 8 +- .../computedPropertiesInDestructuring1.js | 16 +- .../reference/declarationsAndAssignments.js | 6 +- .../destructuringAssignmentWithDefault.js | 2 +- .../emptyAssignmentPatterns02_ES5.js | 4 +- .../emptyAssignmentPatterns04_ES5.js | 5 +- .../initializePropertiesWithRenamedLet.js | 5 +- .../reference/missingAndExcessProperties.js | 16 +- tests/baselines/reference/objectRest.js | 4 +- .../reference/objectRestAssignment.js | 6 +- .../baselines/reference/objectRestNegative.js | 4 +- ...thandPropertyAssignmentsInDestructuring.js | 40 +- 25 files changed, 889 insertions(+), 1396 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 3e65b547d5b..9a477f05211 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -570,6 +570,31 @@ namespace ts { } } + function bindEach(nodes: NodeArray) { + if (nodes === undefined) { + return; + } + + if (skipTransformFlagAggregation) { + forEach(nodes, bind); + } + else { + const savedSubtreeTransformFlags = subtreeTransformFlags; + subtreeTransformFlags = TransformFlags.None; + let nodeArrayFlags = TransformFlags.None; + for (const node of nodes) { + bind(node); + nodeArrayFlags |= node.transformFlags & ~TransformFlags.HasComputedFlags; + } + nodes.transformFlags = nodeArrayFlags | TransformFlags.HasComputedFlags; + subtreeTransformFlags |= savedSubtreeTransformFlags; + } + } + + function bindEachChild(node: Node) { + forEachChild(node, bind, bindEach); + } + function bindChildrenWorker(node: Node): void { // Binding of JsDocComment should be done before the current block scope container changes. // because the scope of JsDocComment should not be affected by whether the current node is a @@ -578,7 +603,7 @@ namespace ts { forEach(node.jsDocComments, bind); } if (checkUnreachable(node)) { - forEachChild(node, bind); + bindEachChild(node); return; } switch (node.kind) { @@ -643,7 +668,7 @@ namespace ts { bindCallExpressionFlow(node); break; default: - forEachChild(node, bind); + bindEachChild(node); break; } } @@ -976,7 +1001,7 @@ namespace ts { return undefined; } - function bindbreakOrContinueFlow(node: BreakOrContinueStatement, breakTarget: FlowLabel, continueTarget: FlowLabel) { + function bindBreakOrContinueFlow(node: BreakOrContinueStatement, breakTarget: FlowLabel, continueTarget: FlowLabel) { const flowLabel = node.kind === SyntaxKind.BreakStatement ? breakTarget : continueTarget; if (flowLabel) { addAntecedent(flowLabel, currentFlow); @@ -990,11 +1015,11 @@ namespace ts { const activeLabel = findActiveLabel(node.label.text); if (activeLabel) { activeLabel.referenced = true; - bindbreakOrContinueFlow(node, activeLabel.breakTarget, activeLabel.continueTarget); + bindBreakOrContinueFlow(node, activeLabel.breakTarget, activeLabel.continueTarget); } } else { - bindbreakOrContinueFlow(node, currentBreakTarget, currentContinueTarget); + bindBreakOrContinueFlow(node, currentBreakTarget, currentContinueTarget); } } @@ -1062,6 +1087,8 @@ namespace ts { } function bindCaseBlock(node: CaseBlock): void { + const savedSubtreeTransformFlags = subtreeTransformFlags; + subtreeTransformFlags = 0; const clauses = node.clauses; let fallthroughFlow = unreachableFlow; for (let i = 0; i < clauses.length; i++) { @@ -1081,6 +1108,8 @@ namespace ts { errorOnFirstToken(clause, Diagnostics.Fallthrough_case_in_switch); } } + clauses.transformFlags = subtreeTransformFlags | TransformFlags.HasComputedFlags; + subtreeTransformFlags |= savedSubtreeTransformFlags; } function bindCaseClause(node: CaseClause): void { @@ -1088,7 +1117,7 @@ namespace ts { currentFlow = preSwitchCaseFlow; bind(node.expression); currentFlow = saveCurrentFlow; - forEach(node.statements, bind); + bindEach(node.statements); } function pushActiveLabel(name: string, breakTarget: FlowLabel, continueTarget: FlowLabel): ActiveLabel { @@ -1180,12 +1209,12 @@ namespace ts { const saveTrueTarget = currentTrueTarget; currentTrueTarget = currentFalseTarget; currentFalseTarget = saveTrueTarget; - forEachChild(node, bind); + bindEachChild(node); currentFalseTarget = currentTrueTarget; currentTrueTarget = saveTrueTarget; } else { - forEachChild(node, bind); + bindEachChild(node); if (node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) { bindAssignmentTargetFlow(node.operand); } @@ -1193,7 +1222,7 @@ namespace ts { } function bindPostfixUnaryExpressionFlow(node: PostfixUnaryExpression) { - forEachChild(node, bind); + bindEachChild(node); if (node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) { bindAssignmentTargetFlow(node.operand); } @@ -1212,7 +1241,7 @@ namespace ts { } } else { - forEachChild(node, bind); + bindEachChild(node); if (isAssignmentOperator(operator) && !isAssignmentTarget(node)) { bindAssignmentTargetFlow(node.left); if (operator === SyntaxKind.EqualsToken && node.left.kind === SyntaxKind.ElementAccessExpression) { @@ -1226,7 +1255,7 @@ namespace ts { } function bindDeleteExpressionFlow(node: DeleteExpression) { - forEachChild(node, bind); + bindEachChild(node); if (node.expression.kind === SyntaxKind.PropertyAccessExpression) { bindAssignmentTargetFlow(node.expression); } @@ -1261,7 +1290,7 @@ namespace ts { } function bindVariableDeclarationFlow(node: VariableDeclaration) { - forEachChild(node, bind); + bindEachChild(node); if (node.initializer || node.parent.parent.kind === SyntaxKind.ForInStatement || node.parent.parent.kind === SyntaxKind.ForOfStatement) { bindInitializedVariableFlow(node); } @@ -1276,12 +1305,12 @@ namespace ts { expr = (expr).expression; } if (expr.kind === SyntaxKind.FunctionExpression || expr.kind === SyntaxKind.ArrowFunction) { - forEach(node.typeArguments, bind); - forEach(node.arguments, bind); + bindEach(node.typeArguments); + bindEach(node.arguments); bind(node.expression); } else { - forEachChild(node, bind); + bindEachChild(node); } if (node.expression.kind === SyntaxKind.PropertyAccessExpression) { const propertyAccess = node.expression; @@ -2514,7 +2543,7 @@ namespace ts { transformFlags |= TransformFlags.AssertTypeScript; } - if (subtreeFlags & TransformFlags.ContainsSpreadExpression + if (subtreeFlags & TransformFlags.ContainsSpread || isSuperOrSuperProperty(expression, expressionKind)) { // If the this node contains a SpreadExpression, or is a super call, then it is an ES6 // node. @@ -2545,7 +2574,7 @@ namespace ts { if (node.typeArguments) { transformFlags |= TransformFlags.AssertTypeScript; } - if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { + if (subtreeFlags & TransformFlags.ContainsSpread) { // If the this node contains a SpreadElementExpression then it is an ES6 // node. transformFlags |= TransformFlags.AssertES2015; @@ -2554,7 +2583,6 @@ namespace ts { return transformFlags & ~TransformFlags.ArrayLiteralOrCallOrNewExcludes; } - function computeBinaryExpression(node: BinaryExpression, subtreeFlags: TransformFlags) { let transformFlags = subtreeFlags; const operatorTokenKind = node.operatorToken.kind; @@ -2601,7 +2629,7 @@ namespace ts { } // parameters with object rest destructuring are ES Next syntax - if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { + if (subtreeFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)) { transformFlags |= TransformFlags.AssertESNext; } @@ -2723,7 +2751,7 @@ namespace ts { } node.transformFlags = transformFlags | TransformFlags.HasComputedFlags; - return transformFlags & ~TransformFlags.NodeExcludes; + return transformFlags & ~TransformFlags.CatchClauseExcludes; } function computeExpressionWithTypeArguments(node: ExpressionWithTypeArguments, subtreeFlags: TransformFlags) { @@ -2839,7 +2867,7 @@ namespace ts { } // function declarations with object rest destructuring are ES Next syntax - if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { + if (subtreeFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)) { transformFlags |= TransformFlags.AssertESNext; } @@ -2881,7 +2909,7 @@ namespace ts { } // function expressions with object rest destructuring are ES Next syntax - if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { + if (subtreeFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)) { transformFlags |= TransformFlags.AssertESNext; } @@ -2924,7 +2952,7 @@ namespace ts { } // arrow functions with object rest destructuring are ES Next syntax - if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { + if (subtreeFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)) { transformFlags |= TransformFlags.AssertESNext; } @@ -3178,16 +3206,19 @@ namespace ts { break; case SyntaxKind.SpreadElement: + transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsSpread; + break; + case SyntaxKind.SpreadAssignment: - // This node is ES6 or ES next syntax, but is handled by a containing node. - transformFlags |= TransformFlags.ContainsSpreadExpression; + transformFlags |= TransformFlags.AssertESNext | TransformFlags.ContainsSpread | TransformFlags.ContainsObjectSpread; break; case SyntaxKind.BindingElement: - if ((node as BindingElement).dotDotDotToken) { - // this node is ES2015 or ES next syntax, but is handled by a containing node. - transformFlags |= TransformFlags.ContainsSpreadExpression; + transformFlags |= TransformFlags.AssertES2015; + if ((node).dotDotDotToken) { + transformFlags |= TransformFlags.ContainsRest; } + break; case SyntaxKind.SuperKeyword: // This node is ES6 syntax. @@ -3200,14 +3231,16 @@ namespace ts { break; case SyntaxKind.ObjectBindingPattern: + transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern; + if (subtreeFlags & TransformFlags.ContainsSpread) { + transformFlags |= TransformFlags.AssertESNext | TransformFlags.ContainsObjectRest; + } + excludeFlags = TransformFlags.BindingPatternExcludes; + break; + case SyntaxKind.ArrayBindingPattern: - // These nodes are ES2015 or ES Next syntax. - if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { - transformFlags |= TransformFlags.AssertESNext | TransformFlags.ContainsBindingPattern; - } - else { - transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern; - } + transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern; + excludeFlags = TransformFlags.BindingPatternExcludes; break; case SyntaxKind.Decorator: @@ -3229,10 +3262,10 @@ namespace ts { transformFlags |= TransformFlags.ContainsLexicalThis; } - if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { + if (subtreeFlags & TransformFlags.ContainsSpread) { // If an ObjectLiteralExpression contains a spread element, then it // is an ES next node. - transformFlags |= TransformFlags.AssertESNext; + transformFlags |= TransformFlags.AssertESNext | TransformFlags.ContainsObjectSpread; } break; @@ -3240,7 +3273,7 @@ namespace ts { case SyntaxKind.ArrayLiteralExpression: case SyntaxKind.NewExpression: excludeFlags = TransformFlags.ArrayLiteralOrCallOrNewExcludes; - if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { + if (subtreeFlags & TransformFlags.ContainsSpread) { // If the this node contains a SpreadExpression, then it is an ES6 // node. transformFlags |= TransformFlags.AssertES2015; @@ -3333,6 +3366,11 @@ namespace ts { return TransformFlags.TypeExcludes; case SyntaxKind.ObjectLiteralExpression: return TransformFlags.ObjectLiteralExcludes; + case SyntaxKind.CatchClause: + return TransformFlags.CatchClauseExcludes; + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: + return TransformFlags.BindingPatternExcludes; default: return TransformFlags.NodeExcludes; } diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 6674ffc7263..ac3d5ed6e29 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -2341,6 +2341,13 @@ namespace ts { // Utilities + export function convertToFunctionBody(node: ConciseBody) { + if (isBlock(node)) { + return node; + } + return createBlock([createReturn(node, node)], node); + } + function isUseStrictPrologue(node: ExpressionStatement): boolean { return (node.expression as StringLiteral).text === "use strict"; } @@ -3121,7 +3128,7 @@ namespace ts { } addCaptureThisForNodeIfNeeded(statements, node, enableSubstitutionsForCapturedThis); - addDefaultValueAssignmentsIfNeeded(statements, node, visitor, convertObjectRest); + addDefaultValueAssignmentsIfNeeded(context, statements, node, visitor, convertObjectRest); addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false); // If we added any generated statements, this must be a multi-line block. @@ -3236,7 +3243,8 @@ namespace ts { * @param statements The statements for the new function body. * @param node A function-like node. */ - export function addDefaultValueAssignmentsIfNeeded(statements: Statement[], + export function addDefaultValueAssignmentsIfNeeded(context: TransformationContext, + statements: Statement[], node: FunctionLikeDeclaration, visitor: (node: Node) => VisitResult, convertObjectRest: boolean): void { @@ -3254,7 +3262,7 @@ namespace ts { } if (isBindingPattern(name)) { - addDefaultValueAssignmentForBindingPattern(statements, parameter, name, initializer, visitor, convertObjectRest); + addDefaultValueAssignmentForBindingPattern(context, statements, parameter, name, initializer, visitor, convertObjectRest); } else if (initializer) { addDefaultValueAssignmentForInitializer(statements, parameter, name, initializer, visitor); @@ -3270,7 +3278,8 @@ namespace ts { * @param name The name of the parameter. * @param initializer The initializer for the parameter. */ - function addDefaultValueAssignmentForBindingPattern(statements: Statement[], + function addDefaultValueAssignmentForBindingPattern(context: TransformationContext, + statements: Statement[], parameter: ParameterDeclaration, name: BindingPattern, initializer: Expression, visitor: (node: Node) => VisitResult, @@ -3286,7 +3295,17 @@ namespace ts { createVariableStatement( /*modifiers*/ undefined, createVariableDeclarationList( - flattenParameterDestructuring(parameter, temp, visitor, convertObjectRest) + flattenDestructuringToDeclarations( + context, + parameter, + temp, + /*skipInitializer*/ convertObjectRest, + /*recordTempVariablesInLine*/ true, + convertObjectRest + ? FlattenLevel.ObjectRest + : FlattenLevel.All, + visitor + ) ) ), EmitFlags.CustomPrologue @@ -3490,12 +3509,16 @@ namespace ts { if (firstOriginalDeclaration && isBindingPattern(firstOriginalDeclaration.name)) { // This works whether the declaration is a var, let, or const. // It will use rhsIterationValue _a[_i] as the initializer. - const declarations = flattenVariableDestructuring( + const declarations = flattenDestructuringToDeclarations( + context, firstOriginalDeclaration, elementAccess, - visitor, - /*recordTempVariable*/ undefined, + /*skipInitializer*/ false, + /*recordTempVariablesInLine*/ true, convertObjectRest + ? FlattenLevel.ObjectRest + : FlattenLevel.All, + visitor ); const declarationList = createVariableDeclarationList(declarations, /*location*/ initializer); @@ -3543,13 +3566,15 @@ namespace ts { // This is a destructuring pattern, so we flatten the destructuring instead. statements.push( createStatement( - flattenDestructuringAssignment( + flattenDestructuringToExpression( context, assignment, /*needsValue*/ false, - context.hoistVariableDeclaration, - visitor, convertObjectRest + ? FlattenLevel.ObjectRest + : FlattenLevel.All, + /*createAssignmentCallback*/ undefined, + visitor ) ) ); diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index b0cb3f9d239..d4886457062 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -3,685 +3,218 @@ /*@internal*/ namespace ts { - type EffectiveBindingElement = VariableDeclaration | ParameterDeclaration | BindingElement | ObjectLiteralElementLike | Expression; - type EffectiveObjectBindingPattern = ObjectBindingPattern | ObjectLiteralExpression; - type EffectiveArrayBindingPattern = ArrayBindingPattern | ArrayLiteralExpression; - type EffectiveBindingPattern = EffectiveObjectBindingPattern | EffectiveArrayBindingPattern; - type EffectiveBindingTarget = EffectiveBindingPattern | Expression; - type EffectiveRestIndicator = DotDotDotToken | SpreadElement | SpreadAssignment; - - export const enum FlattenLevel { - All, - ObjectRestDestructuringOnly, - } - - /** - * Flattens a destructuring assignment expression. - * - * @param root The destructuring assignment expression. - * @param needsValue Indicates whether the value from the right-hand-side of the - * destructuring assignment is needed as part of a larger expression. - * @param recordTempVariable A callback used to record new temporary variables. - * @param visitor An optional visitor to use to visit expressions. - */ - export function flattenDestructuringAssignment( - context: TransformationContext, - node: BinaryExpression, - needsValue: boolean, - recordTempVariable: (node: Identifier) => void, - visitor?: (node: Node) => VisitResult, - transformRest?: boolean): Expression { - - if (isEmptyObjectLiteralOrArrayLiteral(node.left)) { - const right = node.right; - if (isDestructuringAssignment(right)) { - return flattenDestructuringAssignment(context, right, needsValue, recordTempVariable, visitor); - } - else { - return node.right; - } - } - - let location: TextRange = node; - let value = node.right; - const expressions: Expression[] = []; - if (needsValue) { - // If the right-hand value of the destructuring assignment needs to be preserved (as - // is the case when the destructuring assignmen) is part of a larger expression), - // then we need to cache the right-hand value. - // - // The source map location for the assignment should point to the entire binary - // expression. - value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment, visitor); - } - else if (nodeIsSynthesized(node)) { - // Generally, the source map location for a destructuring assignment is the root - // expression. - // - // However, if the root expression is synthesized (as in the case - // of the initializer when transforming a ForOfStatement), then the source map - // location should point to the right-hand value of the expression. - location = value; - } - - flattenDestructuringOld(node, value, location, emitAssignment, emitTempVariableAssignment, recordTempVariable, emitRestAssignment, transformRest, visitor); - - if (needsValue) { - expressions.push(value); - } - - const expression = inlineExpressions(expressions); - aggregateTransformFlags(expression); - return expression; - - function emitAssignment(name: Identifier | ObjectLiteralExpression, value: Expression, location: TextRange) { - const expression = createAssignment(name, value, location); - - // NOTE: this completely disables source maps, but aligns with the behavior of - // `emitAssignment` in the old emitter. - setEmitFlags(expression, EmitFlags.NoNestedSourceMaps); - - aggregateTransformFlags(expression); - expressions.push(expression); - } - - function emitTempVariableAssignment(value: Expression, location: TextRange) { - const name = createTempVariable(recordTempVariable); - emitAssignment(name, value, location); - return name; - } - - function emitRestAssignment(elements: ObjectLiteralElementLike[], value: Expression, location: TextRange) { - emitAssignment(createObjectLiteral(elements), value, location); - } - } - - /** - * Flattens binding patterns in a parameter declaration. - * - * @param node The ParameterDeclaration to flatten. - * @param value The rhs value for the binding pattern. - * @param visitor An optional visitor to use to visit expressions. - */ - export function flattenParameterDestructuring( - node: ParameterDeclaration, - value: Expression, - visitor?: (node: Node) => VisitResult, - transformRest?: boolean) { - const declarations: VariableDeclaration[] = []; - - flattenDestructuringOld(node, value, node, emitAssignment, emitTempVariableAssignment, noop, emitRestAssignment, transformRest, visitor); - - return declarations; - - function emitAssignment(name: Identifier | BindingPattern, value: Expression, location: TextRange) { - const declaration = createVariableDeclaration(name, /*type*/ undefined, value, location); - - // NOTE: this completely disables source maps, but aligns with the behavior of - // `emitAssignment` in the old emitter. - setEmitFlags(declaration, EmitFlags.NoNestedSourceMaps); - - aggregateTransformFlags(declaration); - declarations.push(declaration); - } - - function emitTempVariableAssignment(value: Expression, location: TextRange) { - const name = createTempVariable(/*recordTempVariable*/ undefined); - emitAssignment(name, value, location); - return name; - } - - function emitRestAssignment(elements: BindingElement[], value: Expression, location: TextRange) { - emitAssignment(createObjectBindingPattern(elements), value, location); - } - } - - /** - * Flattens binding patterns in a variable declaration. - * - * @param node The VariableDeclaration to flatten. - * @param value An optional rhs value for the binding pattern. - * @param visitor An optional visitor to use to visit expressions. - */ - export function flattenVariableDestructuring( - node: VariableDeclaration, - value?: Expression, - visitor?: (node: Node) => VisitResult, - recordTempVariable?: (node: Identifier) => void, - transformRest?: boolean) { - const declarations: VariableDeclaration[] = []; - - let pendingAssignments: Expression[]; - flattenDestructuringOld(node, value, node, emitAssignment, emitTempVariableAssignment, recordTempVariable, emitRestAssignment, transformRest, visitor); - - return declarations; - - function emitAssignment(name: Identifier | BindingPattern, value: Expression, location: TextRange, original: Node) { - if (pendingAssignments) { - pendingAssignments.push(value); - value = inlineExpressions(pendingAssignments); - pendingAssignments = undefined; - } - - const declaration = createVariableDeclaration(name, /*type*/ undefined, value, location); - declaration.original = original; - - // NOTE: this completely disables source maps, but aligns with the behavior of - // `emitAssignment` in the old emitter. - setEmitFlags(declaration, EmitFlags.NoNestedSourceMaps); - - declarations.push(declaration); - aggregateTransformFlags(declaration); - } - - function emitTempVariableAssignment(value: Expression, location: TextRange) { - const name = createTempVariable(recordTempVariable); - if (recordTempVariable) { - const assignment = createAssignment(name, value, location); - if (pendingAssignments) { - pendingAssignments.push(assignment); - } - else { - pendingAssignments = [assignment]; - } - } - else { - emitAssignment(name, value, location, /*original*/ undefined); - } - return name; - } - - function emitRestAssignment(elements: BindingElement[], value: Expression, location: TextRange, original: Node) { - emitAssignment(createObjectBindingPattern(elements), value, location, original); - } - } - - /** - * Flattens binding patterns in a variable declaration and transforms them into an expression. - * - * @param node The VariableDeclaration to flatten. - * @param recordTempVariable A callback used to record new temporary variables. - * @param createAssignmentCallback An optional callback used to create assignment expressions - * for non-temporary variables. - * @param visitor An optional visitor to use to visit expressions. - */ - export function flattenVariableDestructuringToExpression( - node: VariableDeclaration, - recordTempVariable: (name: Identifier) => void, - createAssignmentCallback?: (name: Identifier, value: Expression, location?: TextRange) => Expression, - visitor?: (node: Node) => VisitResult) { - - const pendingAssignments: Expression[] = []; - - flattenDestructuringOld(node, /*value*/ undefined, node, emitAssignment, emitTempVariableAssignment, noop, emitRestAssignment, /*transformRest*/ false, visitor); - - const expression = inlineExpressions(pendingAssignments); - aggregateTransformFlags(expression); - return expression; - - function emitAssignment(name: Identifier | ObjectLiteralExpression, value: Expression, location: TextRange, original: Node) { - const expression = createAssignmentCallback - ? createAssignmentCallback(name.kind === SyntaxKind.Identifier ? name : emitTempVariableAssignment(name, location), - value, - location) - : createAssignment(name, value, location); - - emitPendingAssignment(expression, original); - } - - function emitTempVariableAssignment(value: Expression, location: TextRange) { - const name = createTempVariable(recordTempVariable); - emitPendingAssignment(createAssignment(name, value, location), /*original*/ undefined); - return name; - } - - function emitRestAssignment(elements: ObjectLiteralElementLike[], value: Expression, location: TextRange, original: Node) { - emitAssignment(createObjectLiteral(elements), value, location, original); - } - - function emitPendingAssignment(expression: Expression, original: Node) { - expression.original = original; - - // NOTE: this completely disables source maps, but aligns with the behavior of - // `emitAssignment` in the old emitter. - setEmitFlags(expression, EmitFlags.NoNestedSourceMaps); - - pendingAssignments.push(expression); - } - } - - function flattenDestructuringOld( - root: VariableDeclaration | ParameterDeclaration | BindingElement | BinaryExpression, - value: Expression, - location: TextRange, - emitAssignment: (name: Identifier, value: Expression, location: TextRange, original: Node) => void, - emitTempVariableAssignment: (value: Expression, location: TextRange) => Identifier, - recordTempVariable: (node: Identifier) => void, - emitRestAssignment: (elements: (ObjectLiteralElementLike[] | BindingElement[]), value: Expression, location: TextRange, original: Node) => void, - transformRest: boolean, - visitor?: (node: Node) => VisitResult) { - if (value && visitor) { - value = visitNode(value, visitor, isExpression); - } - - if (isBinaryExpression(root)) { - emitDestructuringAssignment(root.left, value, location); - } - else { - emitBindingElement(root, value); - } - - function emitDestructuringAssignment(bindingTarget: Expression | ShorthandPropertyAssignment, value: Expression, location: TextRange) { - // When emitting target = value use source map node to highlight, including any temporary assignments needed for this - let target: Expression; - if (isShorthandPropertyAssignment(bindingTarget)) { - const initializer = visitor - ? visitNode(bindingTarget.objectAssignmentInitializer, visitor, isExpression) - : bindingTarget.objectAssignmentInitializer; - - if (initializer) { - value = createDefaultValueCheck(value, initializer, location); - } - - target = bindingTarget.name; - } - else if (isBinaryExpression(bindingTarget) && bindingTarget.operatorToken.kind === SyntaxKind.EqualsToken) { - const initializer = visitor - ? visitNode(bindingTarget.right, visitor, isExpression) - : bindingTarget.right; - - value = createDefaultValueCheck(value, initializer, location); - target = bindingTarget.left; - } - else { - target = bindingTarget; - } - - if (target.kind === SyntaxKind.ObjectLiteralExpression) { - emitObjectLiteralAssignment(target, value, location); - } - else if (target.kind === SyntaxKind.ArrayLiteralExpression) { - emitArrayLiteralAssignment(target, value, location); - } - else { - const name = getMutableClone(target); - setSourceMapRange(name, target); - setCommentRange(name, target); - emitAssignment(name, value, location, /*original*/ undefined); - } - } - - function emitObjectLiteralAssignment(target: ObjectLiteralExpression, value: Expression, location: TextRange) { - const properties = target.properties; - if (properties.length !== 1) { - // For anything but a single element destructuring we need to generate a temporary - // to ensure value is evaluated exactly once. - // When doing so we want to hightlight the passed in source map node since thats the one needing this temp assignment - value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); - } - - let bindingElements: ObjectLiteralElementLike[] = []; - for (let i = 0; i < properties.length; i++) { - const p = properties[i]; - if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { - if (!transformRest || - p.transformFlags & TransformFlags.ContainsSpreadExpression || - (p.kind === SyntaxKind.PropertyAssignment && p.initializer.transformFlags & TransformFlags.ContainsSpreadExpression)) { - if (bindingElements.length) { - emitRestAssignment(bindingElements, value, location, target); - bindingElements = []; - } - const propName = (p).name; - const bindingTarget = p.kind === SyntaxKind.ShorthandPropertyAssignment ? p : (p).initializer || propName; - // Assignment for bindingTarget = value.propName should highlight whole property, hence use p as source map node - emitDestructuringAssignment(bindingTarget, createDestructuringPropertyAccess(value, propName), p); - } - else { - bindingElements.push(p); - } - } - else if (i === properties.length - 1 && p.kind === SyntaxKind.SpreadAssignment) { - Debug.assert((p as SpreadAssignment).expression.kind === SyntaxKind.Identifier); - if (bindingElements.length) { - emitRestAssignment(bindingElements, value, location, target); - bindingElements = []; - } - const propName = (p as SpreadAssignment).expression as Identifier; - const restCall = createRestCall(value, target.properties, p => p.name, target); - emitDestructuringAssignment(propName, restCall, p); - } - } - if (bindingElements.length) { - emitRestAssignment(bindingElements, value, location, target); - bindingElements = []; - } - } - - function emitArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression, location: TextRange) { - if (transformRest) { - emitESNextArrayLiteralAssignment(target, value, location); - } - else { - emitES2015ArrayLiteralAssignment(target, value, location); - } - } - - function emitESNextArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression, location: TextRange) { - const elements = target.elements; - const numElements = elements.length; - if (numElements !== 1) { - // For anything but a single element destructuring we need to generate a temporary - // to ensure value is evaluated exactly once. - // When doing so we want to highlight the passed-in source map node since thats the one needing this temp assignment - value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); - } - - const expressions: Expression[] = []; - const spreadContainingExpressions: [Expression, Identifier][] = []; - for (let i = 0; i < numElements; i++) { - const e = elements[i]; - if (e.kind === SyntaxKind.OmittedExpression) { - continue; - } - if (e.transformFlags & TransformFlags.ContainsSpreadExpression && i < numElements - 1) { - const tmp = createTempVariable(recordTempVariable); - spreadContainingExpressions.push([e, tmp]); - expressions.push(tmp); - } - else { - expressions.push(e); - } - } - emitAssignment(updateArrayLiteral(target, expressions) as any as Identifier, value, undefined, undefined); - for (const [e, tmp] of spreadContainingExpressions) { - emitDestructuringAssignment(e, tmp, e); - } - } - - function emitES2015ArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression, location: TextRange) { - const elements = target.elements; - const numElements = elements.length; - if (numElements !== 1) { - // For anything but a single element destructuring we need to generate a temporary - // to ensure value is evaluated exactly once. - // When doing so we want to highlight the passed-in source map node since thats the one needing this temp assignment - value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); - } - - for (let i = 0; i < numElements; i++) { - const e = elements[i]; - if (e.kind !== SyntaxKind.OmittedExpression) { - // Assignment for target = value.propName should highligh whole property, hence use e as source map node - if (e.kind !== SyntaxKind.SpreadElement) { - emitDestructuringAssignment(e, createElementAccess(value, createLiteral(i)), e); - } - else if (i === numElements - 1) { - emitDestructuringAssignment((e).expression, createArraySlice(value, i), e); - } - } - } - } - - /** Given value: o, propName: p, pattern: { a, b, ...p } from the original statement - * `{ a, b, ...p } = o`, create `p = __rest(o, ["a", "b"]);`*/ - function createRestCall(value: Expression, elements: T[], getPropertyName: (element: T) => PropertyName, location: TextRange): Expression { - const propertyNames: LiteralExpression[] = []; - for (let i = 0; i < elements.length - 1; i++) { - if (isOmittedExpression(elements[i])) { - continue; - } - const str = createSynthesizedNode(SyntaxKind.StringLiteral); - str.pos = location.pos; - str.end = location.end; - str.text = getTextOfPropertyName(getPropertyName(elements[i])); - propertyNames.push(str); - } - const args = createSynthesizedNodeArray([value, createArrayLiteral(propertyNames, location)]); - return createCall(createIdentifier("__rest"), undefined, args); - } - - function emitBindingElement(target: VariableDeclaration | ParameterDeclaration | BindingElement, value: Expression) { - // Any temporary assignments needed to emit target = value should point to target - const initializer = visitor ? visitNode(target.initializer, visitor, isExpression) : target.initializer; - if (transformRest) { - value = value || initializer; - } - else if (initializer) { - // Combine value and initializer - value = value ? createDefaultValueCheck(value, initializer, target) : initializer; - } - else if (!value) { - // Use 'void 0' in absence of value and initializer - value = createVoidZero(); - } - - const name = target.name; - if (!isBindingPattern(name)) { - emitAssignment(name, value, target, target); - } - else { - const numElements = name.elements.length; - if (numElements !== 1) { - // For anything other than a single-element destructuring we need to generate a temporary - // to ensure value is evaluated exactly once. Additionally, if we have zero elements - // we need to emit *something* to ensure that in case a 'var' keyword was already emitted, - // so in that case, we'll intentionally create that temporary. - value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ numElements !== 0, target, emitTempVariableAssignment); - } - if (name.kind === SyntaxKind.ArrayBindingPattern) { - emitArrayBindingElement(name as ArrayBindingPattern, value); - } - else { - emitObjectBindingElement(target, value); - } - } - } - - function emitArrayBindingElement(name: ArrayBindingPattern, value: Expression) { - if (transformRest) { - emitESNextArrayBindingElement(name, value); - } - else { - emitES2015ArrayBindingElement(name, value); - } - } - - function emitES2015ArrayBindingElement(name: ArrayBindingPattern, value: Expression) { - const elements = name.elements; - const numElements = elements.length; - for (let i = 0; i < numElements; i++) { - const element = elements[i]; - if (isOmittedExpression(element)) { - continue; - } - if (!element.dotDotDotToken) { - // Rewrite element to a declaration that accesses array element at index i - emitBindingElement(element, createElementAccess(value, i)); - } - else if (i === numElements - 1) { - emitBindingElement(element, createArraySlice(value, i)); - } - } - } - - function emitESNextArrayBindingElement(name: ArrayBindingPattern, value: Expression) { - const elements = name.elements; - const numElements = elements.length; - const bindingElements: BindingElement[] = []; - const spreadContainingElements: BindingElement[] = []; - for (let i = 0; i < numElements; i++) { - const element = elements[i]; - if (isOmittedExpression(element)) { - continue; - } - if (element.transformFlags & TransformFlags.ContainsSpreadExpression && i < numElements - 1) { - spreadContainingElements.push(element); - bindingElements.push(createBindingElement(undefined, undefined, getGeneratedNameForNode(element), undefined, value)); - } - else { - bindingElements.push(element); - } - } - emitAssignment(updateArrayBindingPattern(name, bindingElements) as any as Identifier, value, undefined, undefined); - for (const element of spreadContainingElements) { - emitBindingElement(element, getGeneratedNameForNode(element)); - } - } - - function emitObjectBindingElement(target: VariableDeclaration | ParameterDeclaration | BindingElement, value: Expression) { - const name = target.name as BindingPattern; - const elements = name.elements; - const numElements = elements.length; - let bindingElements: BindingElement[] = []; - for (let i = 0; i < numElements; i++) { - const element = elements[i]; - if (isOmittedExpression(element)) { - continue; - } - if (i === numElements - 1 && element.dotDotDotToken) { - if (bindingElements.length) { - emitRestAssignment(bindingElements, value, target, target); - bindingElements = []; - } - const restCall = createRestCall(value, - name.elements, - element => (element as BindingElement).propertyName || (element as BindingElement).name, - name); - emitBindingElement(element, restCall); - } - else if (transformRest && !(element.transformFlags & TransformFlags.ContainsSpreadExpression)) { - // do not emit until we have a complete bundle of ES2015 syntax - bindingElements.push(element); - } - else { - if (bindingElements.length) { - emitRestAssignment(bindingElements, value, target, target); - bindingElements = []; - } - // Rewrite element to a declaration with an initializer that fetches property - const propName = element.propertyName || element.name; - emitBindingElement(element, createDestructuringPropertyAccess(value, propName)); - } - } - if (bindingElements.length) { - emitRestAssignment(bindingElements, value, target, target); - bindingElements = []; - } - } - - function createDefaultValueCheck(value: Expression, defaultValue: Expression, location: TextRange): Expression { - value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); - return createConditional( - createStrictEquality(value, createVoidZero()), - createToken(SyntaxKind.QuestionToken), - defaultValue, - createToken(SyntaxKind.ColonToken), - value - ); - } - - /** - * Creates either a PropertyAccessExpression or an ElementAccessExpression for the - * right-hand side of a transformed destructuring assignment. - * - * @param expression The right-hand expression that is the source of the property. - * @param propertyName The destructuring property name. - */ - function createDestructuringPropertyAccess(expression: Expression, propertyName: PropertyName): LeftHandSideExpression { - if (isComputedPropertyName(propertyName)) { - return createElementAccess( - expression, - ensureIdentifierOld(propertyName.expression, /*reuseIdentifierExpressions*/ false, /*location*/ propertyName, emitTempVariableAssignment) - ); - } - else if (isLiteralExpression(propertyName)) { - const clone = getSynthesizedClone(propertyName); - clone.text = unescapeIdentifier(clone.text); - return createElementAccess(expression, clone); - } - else { - if (isGeneratedIdentifier(propertyName)) { - const clone = getSynthesizedClone(propertyName); - clone.text = unescapeIdentifier(clone.text); - return createPropertyAccess(expression, clone); - } - else { - return createPropertyAccess(expression, createIdentifier(unescapeIdentifier(propertyName.text))); - } - } - } - } - - /** - * Ensures that there exists a declared identifier whose value holds the given expression. - * This function is useful to ensure that the expression's value can be read from in subsequent expressions. - * Unless 'reuseIdentifierExpressions' is false, 'value' will be returned if it is just an identifier. - * - * @param value the expression whose value needs to be bound. - * @param reuseIdentifierExpressions true if identifier expressions can simply be returned; - * false if it is necessary to always emit an identifier. - * @param location The location to use for source maps and comments. - * @param emitTempVariableAssignment A callback used to emit a temporary variable. - * @param visitor An optional callback used to visit the value. - */ - function ensureIdentifierOld( - value: Expression, - reuseIdentifierExpressions: boolean, - location: TextRange, - emitTempVariableAssignment: (value: Expression, location: TextRange) => Identifier, - visitor?: (node: Node) => VisitResult) { - - if (isIdentifier(value) && reuseIdentifierExpressions) { - return value; - } - else { - if (visitor) { - value = visitNode(value, visitor, isExpression); - } - - return emitTempVariableAssignment(value, location); - } - } + type EffectiveBindingOrAssignmentElement = VariableDeclaration | ParameterDeclaration | BindingElement | ObjectLiteralElementLike | Expression; + type EffectiveObjectBindingOrAssignmentPattern = ObjectBindingPattern | ObjectLiteralExpression; + type EffectiveArrayBindingOrAssignmentPattern = ArrayBindingPattern | ArrayLiteralExpression; + type EffectiveBindingOrAssignmentPattern = EffectiveObjectBindingOrAssignmentPattern | EffectiveArrayBindingOrAssignmentPattern; + type EffectiveBindingOrAssignmentTarget = EffectiveBindingOrAssignmentPattern | Expression; + type EffectiveBindingOrAssignmentRestIndicator = DotDotDotToken | SpreadElement | SpreadAssignment; interface FlattenHost { context: TransformationContext; level: FlattenLevel; recordTempVariablesInLine: boolean; - emitAssignment: (target: EffectiveBindingTarget, value: Expression, location: TextRange, original: Node) => void; - emitArrayAssignment: (elements: EffectiveBindingElement[], value: Expression, location: TextRange, original: Node) => void; - emitObjectAssignment: (elements: EffectiveBindingElement[], value: Expression, location: TextRange, original: Node) => void; emitExpression: (value: Expression) => void; + emitBindingOrAssignment: (target: EffectiveBindingOrAssignmentTarget, value: Expression, location: TextRange, original: Node) => void; + createArrayBindingOrAssignmentPattern: (elements: EffectiveBindingOrAssignmentElement[]) => EffectiveArrayBindingOrAssignmentPattern; + createObjectBindingOrAssignmentPattern: (elements: EffectiveBindingOrAssignmentElement[]) => EffectiveObjectBindingOrAssignmentPattern; + createArrayBindingOrAssignmentElement: (node: Identifier) => EffectiveBindingOrAssignmentElement; + visitor?: (node: Node) => VisitResult; } + export const enum FlattenLevel { + ObjectRest, + All, + } + + export const enum FlattenOutput { + Expression, + Declarations + } + + export const enum FlattenOptions { + NeedsValue = 1 << 0, + SkipInitializer = 1 << 1, + RecordTempVariablesInLine = 1 << 2, + } + + export function flattenDestructuring( + output: FlattenOutput.Expression, + level: FlattenLevel, + node: VariableDeclaration | DestructuringAssignment, + visitor: (node: Node) => VisitResult, + context: TransformationContext, + options: FlattenOptions, + createAssignment?: (name: Identifier, value: Expression, location?: TextRange) => Expression): Expression; + export function flattenDestructuring( + output: FlattenOutput.Declarations, + level: FlattenLevel, + node: VariableDeclaration | ParameterDeclaration, + visitor: (node: Node) => VisitResult, + context: TransformationContext, + options: FlattenOptions, + boundValue?: Expression): VariableDeclaration[]; + export function flattenDestructuring( + _output: FlattenOutput, + _level: FlattenLevel, + _node: VariableDeclaration | ParameterDeclaration | DestructuringAssignment, + _visitor: (node: Node) => VisitResult, + _context: TransformationContext, + _options: FlattenOptions, + _valueOrCallback?: Expression | ((name: Identifier, value: Expression, location?: TextRange) => Expression)): Expression | VariableDeclaration[] { + // const flattenMode = flags & FlattenFlags.FlattenMask; + // const outputMode = flags & FlattenFlags.OutputMask; + // const options = flags & FlattenFlags.OptionsMask; + + + // if (outputMode === FlattenFlags.OutputExpressions) { + // return flattenDestructuringToExpression(context, node, !(options & FlattenFlags.NeedsValue), flattenMode, createAssignmentCallback, visitor); + // } + // else { + // return flattenDestructuringToDeclarations( + // context, + // node, + // boundValue) + // } + return; + } + + /** + * Flattens a DestructuringAssignment or a VariableDeclaration to an expression. + * + * @param context The transformation context + * @param node The node to flatten. + * @param needsValue Indicates whether the value from the right-hand-side of the + * destructuring assignment is needed as part of a larger expression. + * @param level Indicates the extent to which flattening should occur. + * @param createAssignmentCallback A callback used to create the assignment expression. + * @param visitor A visitor used to visit initializers. + */ + export function flattenDestructuringToExpression( + context: TransformationContext, + node: VariableDeclaration | DestructuringAssignment, + needsValue: boolean, + level: FlattenLevel, + createAssignmentCallback: (name: Identifier, value: Expression, location?: TextRange) => Expression, + visitor: (node: Node) => VisitResult): Expression { + + let location: TextRange = node; + let value: Expression; + if (isDestructuringAssignment(node)) { + value = node.right; + while (isEmptyObjectLiteralOrArrayLiteral(node.left)) { + if (isDestructuringAssignment(value)) { + location = node = value; + value = node.right; + } + else { + return value; + } + } + } + + const expressions: Expression[] = []; + const host: FlattenHost = { + context, + level, + recordTempVariablesInLine: false, + emitExpression, + emitBindingOrAssignment, + createArrayBindingOrAssignmentPattern: createEffectiveArrayAssignmentPattern, + createObjectBindingOrAssignmentPattern: createEffectiveObjectAssignmentPattern, + createArrayBindingOrAssignmentElement: createEffectiveAssignmentElement, + visitor + }; + + if (value) { + value = visitNode(value, visitor, isExpression); + if (needsValue) { + // If the right-hand value of the destructuring assignment needs to be preserved (as + // is the case when the destructuring assignment is part of a larger expression), + // then we need to cache the right-hand value. + // + // The source map location for the assignment should point to the entire binary + // expression. + value = ensureIdentifier(host, value, /*reuseIdentifierExpressions*/ true, location); + } + else if (nodeIsSynthesized(node)) { + // Generally, the source map location for a destructuring assignment is the root + // expression. + // + // However, if the root expression is synthesized (as in the case + // of the initializer when transforming a ForOfStatement), then the source map + // location should point to the right-hand value of the expression. + location = value; + } + } + + flattenEffectiveBindingElement(host, node, value, location, /*skipInitializer*/ isDestructuringAssignment(node)); + + if (value && needsValue) { + expressions.push(value); + } + + return aggregateTransformFlags(inlineExpressions(expressions)); + + function emitExpression(expression: Expression) { + // NOTE: this completely disables source maps, but aligns with the behavior of + // `emitAssignment` in the old emitter. + setEmitFlags(expression, EmitFlags.NoNestedSourceMaps); + aggregateTransformFlags(expression); + expressions.push(expression); + } + + function emitBindingOrAssignment(target: EffectiveBindingOrAssignmentTarget, value: Expression, location: TextRange, original: Node) { + Debug.assertNode(target, createAssignmentCallback ? isIdentifier : isExpression); + const expression = createAssignmentCallback + ? createAssignmentCallback(target, value, location) + : createAssignment(visitNode(target, visitor, isExpression), value, location); + expression.original = original; + emitExpression(expression); + } + } + + /** + * Flattens a VariableDeclaration or ParameterDeclaration to one or more variable declarations. + * + * @param context The transformation context + * @param node The node to flatten. + * @param boundValue The value bound to the declaration. + * @param recordTempVariablesInLine Indicates whether temporary variables should be recored in-line. + * @param level Indicates the extent to which flattening should occur. + */ export function flattenDestructuringToDeclarations( context: TransformationContext, node: VariableDeclaration | ParameterDeclaration, boundValue: Expression | undefined, + skipInitializer: boolean, recordTempVariablesInLine: boolean, - level: FlattenLevel): VisitResult { + level: FlattenLevel, + visitor: (node: Node) => VisitResult): VariableDeclaration[] { - const pendingDeclarations: { pendingExpressions?: Expression[], name: BindingName, value: Expression, location?: TextRange, original?: Node; }[] = []; let pendingExpressions: Expression[]; - let declaration: VariableDeclaration; - let declarations: VariableDeclaration[]; + const pendingDeclarations: { pendingExpressions?: Expression[], name: BindingName, value: Expression, location?: TextRange, original?: Node; }[] = []; + const declarations: VariableDeclaration[] = []; const host: FlattenHost = { context, level, recordTempVariablesInLine, emitExpression, - emitAssignment, - emitArrayAssignment, - emitObjectAssignment + emitBindingOrAssignment, + createArrayBindingOrAssignmentPattern: createEffectiveArrayBindingPattern, + createObjectBindingOrAssignmentPattern: createEffectiveObjectBindingPattern, + createArrayBindingOrAssignmentElement: createEffectiveBindingElement, + visitor }; - flattenEffectiveBindingElement(host, node, boundValue, node); + flattenEffectiveBindingElement(host, node, boundValue, node, skipInitializer); if (pendingExpressions) { const temp = createTempVariable(/*recordTempVariable*/ undefined); if (recordTempVariablesInLine) { const value = inlineExpressions(pendingExpressions); pendingExpressions = undefined; - emitAssignment(temp, value, /*location*/ undefined, /*original*/ undefined); + emitBindingOrAssignment(temp, value, /*location*/ undefined, /*original*/ undefined); } else { context.hoistVariableDeclaration(temp); @@ -706,51 +239,33 @@ namespace ts { setEmitFlags(variable, EmitFlags.NoNestedSourceMaps); } aggregateTransformFlags(variable); - if (!declaration) { - declaration = variable; - } - else if (!declarations) { - declarations = [declaration, variable]; - } - else { - declarations.push(variable); - } + declarations.push(variable); } - return declarations || declaration; + return declarations; function emitExpression(value: Expression) { pendingExpressions = append(pendingExpressions, value); } - function emitAssignment(target: EffectiveBindingTarget, value: Expression, location: TextRange, original: Node) { + function emitBindingOrAssignment(target: EffectiveBindingOrAssignmentTarget, value: Expression, location: TextRange, original: Node) { Debug.assertNode(target, isBindingName); - pendingDeclarations.push({ pendingExpressions, name: target, value, location, original }); if (pendingExpressions) { value = inlineExpressions(append(pendingExpressions, value)); pendingExpressions = undefined; } - } - - function emitArrayAssignment(elements: EffectiveBindingElement[], value: Expression, location: TextRange, original: Node) { - Debug.assertEachNode(elements, isArrayBindingElement); - emitAssignment(createArrayBindingPattern(elements), value, location, original); - } - - function emitObjectAssignment(elements: EffectiveBindingElement[], value: Expression, location: TextRange, original: Node) { - Debug.assertEachNode(elements, isBindingElement); - emitAssignment(createObjectBindingPattern(elements), value, location, original); + pendingDeclarations.push({ pendingExpressions, name: target, value, location, original }); } } function flattenEffectiveBindingElement( host: FlattenHost, - bindingElement: EffectiveBindingElement, + bindingElement: EffectiveBindingOrAssignmentElement, boundValue: Expression | undefined, location: TextRange, skipInitializer?: boolean) { if (!skipInitializer) { - const initializer = getInitializerOfEffectiveBindingElement(bindingElement); + const initializer = visitNode(getInitializerOfEffectiveBindingElement(bindingElement), host.visitor, isExpression); if (initializer) { // Combine value and initializer boundValue = boundValue ? createDefaultValueCheck(host, boundValue, initializer, location) : initializer; @@ -762,7 +277,7 @@ namespace ts { } const bindingTarget = getTargetOfEffectiveBindingElement(bindingElement); if (!isEffectiveBindingPattern(bindingTarget)) { - host.emitAssignment(bindingTarget, boundValue, location, /*original*/ bindingElement); + host.emitBindingOrAssignment(bindingTarget, boundValue, location, /*original*/ bindingElement); } else { const elements = getElementsOfEffectiveBindingPattern(bindingTarget); @@ -784,18 +299,20 @@ namespace ts { } } - function flattenEffectiveObjectBindingElements(host: FlattenHost, bindingTarget: EffectiveObjectBindingPattern, elements: EffectiveBindingElement[], boundValue: Expression, location: TextRange) { - let bindingElements: EffectiveBindingElement[]; + function flattenEffectiveObjectBindingElements(host: FlattenHost, bindingTarget: EffectiveObjectBindingOrAssignmentPattern, elements: EffectiveBindingOrAssignmentElement[], boundValue: Expression, location: TextRange) { + let bindingElements: EffectiveBindingOrAssignmentElement[]; const numElements = elements.length; for (let i = 0; i < numElements; i++) { const element = elements[i]; if (!getEffectiveRestIndicator(element)) { - if (host.level >= FlattenLevel.ObjectRestDestructuringOnly && !(element.transformFlags & TransformFlags.ContainsSpreadExpression)) { + if (host.level <= FlattenLevel.ObjectRest + && !(element.transformFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)) + && !(getTargetOfEffectiveBindingElement(element).transformFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest))) { bindingElements = append(bindingElements, element); } else { if (bindingElements) { - host.emitObjectAssignment(bindingElements, boundValue, location, bindingTarget); + host.emitBindingOrAssignment(host.createObjectBindingOrAssignmentPattern(bindingElements), boundValue, location, bindingTarget); bindingElements = undefined; } const propertyName = getEffectivePropertyNameOfEffectiveBindingElement(element); @@ -805,7 +322,7 @@ namespace ts { } else if (i === numElements - 1) { if (bindingElements) { - host.emitObjectAssignment(bindingElements, boundValue, location, bindingTarget); + host.emitBindingOrAssignment(host.createObjectBindingOrAssignmentPattern(bindingElements), boundValue, location, bindingTarget); bindingElements = undefined; } const value = createRestCall(boundValue, elements, bindingTarget); @@ -813,31 +330,29 @@ namespace ts { } } if (bindingElements) { - host.emitObjectAssignment(bindingElements, boundValue, location, bindingTarget); + host.emitBindingOrAssignment(host.createObjectBindingOrAssignmentPattern(bindingElements), boundValue, location, bindingTarget); } } - function flattenEffectiveArrayBindingElements(host: FlattenHost, bindingTarget: EffectiveArrayBindingPattern, elements: EffectiveBindingElement[], boundValue: Expression, location: TextRange) { - let bindingElements: EffectiveBindingElement[]; - let spreadContainingElements: EffectiveBindingElement[]; - let tempNames: Map; + function flattenEffectiveArrayBindingElements(host: FlattenHost, bindingTarget: EffectiveArrayBindingOrAssignmentPattern, elements: EffectiveBindingOrAssignmentElement[], boundValue: Expression, location: TextRange) { + let bindingElements: EffectiveBindingOrAssignmentElement[]; + let spreadContainingElements: [Identifier, EffectiveBindingOrAssignmentElement][]; const numElements = elements.length; for (let i = 0; i < numElements; i++) { const element = elements[i]; - if (isOmittedExpression(element)) { - continue; - } - else if (host.level >= FlattenLevel.ObjectRestDestructuringOnly) { - if (element.transformFlags & TransformFlags.ContainsSpreadExpression) { + if (host.level <= FlattenLevel.ObjectRest) { + if (element.transformFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest) && i < numElements - 1) { const temp = createTempVariable(/*recordTempVariable*/ undefined); - tempNames = appendProperty(tempNames, getNodeId(element), temp); - spreadContainingElements = append(spreadContainingElements, element); - bindingElements = append(bindingElements, temp); + spreadContainingElements = append(spreadContainingElements, <[Identifier, EffectiveBindingOrAssignmentElement]>[temp, element]); + bindingElements = append(bindingElements, host.createArrayBindingOrAssignmentElement(temp)); } else { bindingElements = append(bindingElements, element); } } + else if (isOmittedExpression(element)) { + continue; + } else if (!getEffectiveRestIndicator(element)) { const value = createElementAccess(boundValue, i); flattenEffectiveBindingElement(host, element, value, /*location*/ element); @@ -848,11 +363,11 @@ namespace ts { } } if (bindingElements) { - host.emitArrayAssignment(bindingElements, boundValue, location, bindingTarget); + host.emitBindingOrAssignment(host.createArrayBindingOrAssignmentPattern(bindingElements), boundValue, location, bindingTarget); } if (spreadContainingElements) { - for (const element of spreadContainingElements) { - flattenEffectiveBindingElement(host, element, tempNames[getNodeId(element)], element); + for (const [id, element] of spreadContainingElements) { + flattenEffectiveBindingElement(host, element, id, element); } } } @@ -923,7 +438,7 @@ namespace ts { else { const temp = createTempVariable(/*recordTempVariable*/ undefined); if (host.recordTempVariablesInLine) { - host.emitAssignment(temp, value, location, /*original*/ undefined); + host.emitBindingOrAssignment(temp, value, location, /*original*/ undefined); } else { host.context.hoistVariableDeclaration(temp); @@ -936,7 +451,7 @@ namespace ts { /** * Determines whether the EffectiveBindingElement is a declaration */ - function isDeclarationBindingElement(bindingElement: EffectiveBindingElement): bindingElement is VariableDeclaration | ParameterDeclaration | BindingElement { + function isDeclarationBindingElement(bindingElement: EffectiveBindingOrAssignmentElement): bindingElement is VariableDeclaration | ParameterDeclaration | BindingElement { switch (bindingElement.kind) { case SyntaxKind.VariableDeclaration: case SyntaxKind.Parameter: @@ -950,7 +465,7 @@ namespace ts { /** * Gets the initializer of an EffectiveBindingElement. */ - function getInitializerOfEffectiveBindingElement(bindingElement: EffectiveBindingElement): Expression | undefined { + function getInitializerOfEffectiveBindingElement(bindingElement: EffectiveBindingOrAssignmentElement): Expression | undefined { if (isDeclarationBindingElement(bindingElement)) { // `1` in `let { a = 1 } = ...` // `1` in `let { a: b = 1 } = ...` @@ -992,7 +507,7 @@ namespace ts { /** * Gets the name of an EffectiveBindingElement. */ - function getTargetOfEffectiveBindingElement(bindingElement: EffectiveBindingElement): EffectiveBindingTarget { + function getTargetOfEffectiveBindingElement(bindingElement: EffectiveBindingOrAssignmentElement): EffectiveBindingOrAssignmentTarget { if (isDeclarationBindingElement(bindingElement)) { // `a` in `let { a } = ...` // `a` in `let { a = 1 } = ...` @@ -1067,7 +582,7 @@ namespace ts { /** * Determines whether an EffectiveBindingElement is a rest element. */ - function getEffectiveRestIndicator(bindingElement: EffectiveBindingElement): EffectiveRestIndicator { + function getEffectiveRestIndicator(bindingElement: EffectiveBindingOrAssignmentElement): EffectiveBindingOrAssignmentRestIndicator { switch (bindingElement.kind) { case SyntaxKind.Parameter: case SyntaxKind.BindingElement: @@ -1086,7 +601,7 @@ namespace ts { /** * Gets the property name of a BindingElement-like element */ - function getEffectivePropertyNameOfEffectiveBindingElement(bindingElement: EffectiveBindingElement) { + function getEffectivePropertyNameOfEffectiveBindingElement(bindingElement: EffectiveBindingOrAssignmentElement) { switch (bindingElement.kind) { case SyntaxKind.BindingElement: // `a` in `let { a: b } = ...` @@ -1126,7 +641,7 @@ namespace ts { /** * Determines whether a node is BindingPattern-like */ - function isEffectiveBindingPattern(node: EffectiveBindingTarget): node is EffectiveBindingPattern { + function isEffectiveBindingPattern(node: EffectiveBindingOrAssignmentTarget): node is EffectiveBindingOrAssignmentPattern { return isEffectiveObjectBindingPattern(node) || isEffectiveArrayBindingPattern(node); } @@ -1134,7 +649,7 @@ namespace ts { /** * Determines whether a node is ObjectBindingPattern-like */ - function isEffectiveObjectBindingPattern(node: EffectiveBindingTarget): node is EffectiveObjectBindingPattern { + function isEffectiveObjectBindingPattern(node: EffectiveBindingOrAssignmentTarget): node is EffectiveObjectBindingOrAssignmentPattern { switch (node.kind) { case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ObjectLiteralExpression: @@ -1147,7 +662,7 @@ namespace ts { /** * Determines whether a node is ArrayBindingPattern-like */ - function isEffectiveArrayBindingPattern(node: EffectiveBindingTarget): node is EffectiveArrayBindingPattern { + function isEffectiveArrayBindingPattern(node: EffectiveBindingOrAssignmentTarget): node is EffectiveArrayBindingOrAssignmentPattern { switch (node.kind) { case SyntaxKind.ArrayBindingPattern: case SyntaxKind.ArrayLiteralExpression: @@ -1160,7 +675,7 @@ namespace ts { /** * Gets the elements of a BindingPattern-like name */ - function getElementsOfEffectiveBindingPattern(name: EffectiveBindingPattern): EffectiveBindingElement[] { + function getElementsOfEffectiveBindingPattern(name: EffectiveBindingOrAssignmentPattern): EffectiveBindingOrAssignmentElement[] { switch (name.kind) { case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: @@ -1175,179 +690,79 @@ namespace ts { } } - // function updateEffectiveBindingElement(bindingElement: EffectiveBindingElement, restIndicator: EffectiveRestIndicator, propertyName: PropertyName, target: EffectiveBindingTarget, initializer: Expression) { - // switch (bindingElement.kind) { - // case SyntaxKind.VariableDeclaration: - // Debug.assertNode(target, isBindingName); - // Debug.assertMissingNode(propertyName); - // return updateVariableDeclaration( - // bindingElement, - // target, - // /*type*/ undefined, - // initializer - // ); - - // case SyntaxKind.Parameter: - // Debug.assertOptionalToken(restIndicator, SyntaxKind.DotDotDotToken); - // Debug.assertMissingNode(propertyName); - // Debug.assertNode(target, isBindingName); - // return updateParameter( - // bindingElement, - // /*decorators*/ undefined, - // /*modifiers*/ undefined, - // restIndicator, - // target, - // /*type*/ undefined, - // initializer - // ); - - // case SyntaxKind.BindingElement: - // Debug.assertOptionalToken(restIndicator, SyntaxKind.DotDotDotToken); - // Debug.assertNode(target, isBindingName); - // return updateBindingElement( - // bindingElement, - // restIndicator, - // propertyName, - // target, - // initializer - // ); - - // case SyntaxKind.PropertyAssignment: - // case SyntaxKind.ShorthandPropertyAssignment: - // case SyntaxKind.SpreadAssignment: - // if (restIndicator) { - // return convertToSpreadAssignment(bindingElement, propertyName, target, initializer); - // } - // else if (propertyName) { - // return convertToPropertyAssignment(bindingElement, propertyName, target, initializer); - // } - // else { - // return convertToShorthandPropertyAssignment(bindingElement, target, initializer); - // } - - // case SyntaxKind.ArrayLiteralExpression: - // case SyntaxKind.BinaryExpression: - // case SyntaxKind.SpreadElement: - // case SyntaxKind.PropertyAccessExpression: - // case SyntaxKind.ElementAccessExpression: - // Debug.assertMissingNode(propertyName); - // if (restIndicator) { - // return convertToSpreadElement(bindingElement, target, initializer); - // } - // else { - - // } - // } - // } - - // function convertToSpreadAssignment(node: PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment, propertyName: PropertyName, target: EffectiveBindingTarget, initializer: Expression) { - // Debug.assertMissingNode(propertyName); - // Debug.assertNode(target, isIdentifier); - // Debug.assertMissingNode(initializer); - // if (node.kind === SyntaxKind.SpreadAssignment) { - // return updateSpreadAssignment(node, target); - // } - // return setOriginalNode( - // createSpreadAssignment( - // target, - // node - // ), - // node - // ); - // } - - // function convertToPropertyAssignment(node: PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment, propertyName: PropertyName, target: EffectiveBindingTarget, initializer: Expression) { - // Debug.assertNode(target, isExpression); - // if (node.kind === SyntaxKind.PropertyAssignment) { - // return updatePropertyAssignment( - // node, - // propertyName, - // initializer ? - // isAssignmentExpression(node.initializer, /*excludeCompoundAssignment*/ true) - // ? updateBinary(node.initializer, target, initializer) - // : createAssignment(target, initializer) - // : target - // ); - // } - // return setOriginalNode( - // createPropertyAssignment( - // propertyName, - // initializer ? - // createAssignment(target, initializer) - // : target, - // node - // ), - // node - // ); - // } - - // function convertToShorthandPropertyAssignment(node: PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment, target: EffectiveBindingTarget, initializer: Expression) { - // Debug.assertNode(target, isIdentifier); - // if (node.kind === SyntaxKind.ShorthandPropertyAssignment) { - // return updateShorthandPropertyAssignment( - // node, - // target, - // initializer - // ); - // } - // return setOriginalNode( - // createShorthandPropertyAssignment( - // target, - // initializer, - // node - // ), - // node - // ); - // } - - // function convertToSpreadElement(node: Expression, target: EffectiveBindingTarget, initializer: Expression) { - // Debug.assertNode(target, isExpression); - // Debug.assertMissingNode(initializer); - // if (node.kind === SyntaxKind.SpreadElement) { - // return updateSpread( - // node, - // target); - // } - // return setOriginalNode( - // createSpread( - // target, - // node - // ), - // node - // ); - // } - - // function convertToElement(node: Expression, target: EffectiveBindingTarget, initializer: Expression) { - - // } - - function createOrUpdateVariableDeclaration(node: Node, name: BindingName, initializer: Expression, location: TextRange) { - if (node && node.kind === SyntaxKind.VariableDeclaration) { - return updateVariableDeclaration(node, name, /*type*/ undefined, initializer); - } - const variable = createVariableDeclaration(name, /*type*/ undefined, initializer, location); - return node ? setOriginalNode(variable, node) : variable; + function createEffectiveArrayBindingPattern(elements: EffectiveBindingOrAssignmentElement[]) { + Debug.assertEachNode(elements, isArrayBindingElement); + return createArrayBindingPattern(elements); } - function createOrUpdateArrayBindingPattern(node: Node, elements: ArrayBindingElement[], location: TextRange) { - if (node && node.kind === SyntaxKind.ArrayBindingPattern) { - return updateArrayBindingPattern(node, elements); - } - const pattern = createArrayBindingPattern(elements, location); - return node ? setOriginalNode(pattern, node) : pattern; + function createEffectiveArrayAssignmentPattern(elements: EffectiveBindingOrAssignmentElement[]) { + return createArrayLiteral(map(elements, convertToArrayLiteralElement)); } - function createOrUpdateObjectBindingPattern(node: Node, elements: BindingElement[], location: TextRange) { - if (node && node.kind === SyntaxKind.ArrayBindingPattern) { - return updateObjectBindingPattern(node, elements); + function createEffectiveObjectBindingPattern(elements: EffectiveBindingOrAssignmentElement[]) { + Debug.assertEachNode(elements, isBindingElement); + return createObjectBindingPattern(elements); + } + + function createEffectiveObjectAssignmentPattern(elements: EffectiveBindingOrAssignmentElement[]) { + return createObjectLiteral(map(elements, convertToObjectLiteralElement)); + } + + function createEffectiveBindingElement(name: Identifier) { + return createBindingElement(/*propertyName*/ undefined, /*dotDotDotToken*/ undefined, name); + } + + function createEffectiveAssignmentElement(name: Identifier) { + return name; + } + + function convertToArrayLiteralElement(element: EffectiveBindingOrAssignmentElement) { + if (isBindingElement(element)) { + if (element.dotDotDotToken) { + Debug.assertNode(element.name, isIdentifier); + return setOriginalNode(createSpread(element.name, element), element); + } + const expression = convertToExpressionTarget(element.name); + return element.initializer ? setOriginalNode(createAssignment(expression, element.initializer, element), element) : expression; } - const pattern = createObjectBindingPattern(elements, location); - return node ? setOriginalNode(pattern, node) : pattern; + Debug.assertNode(element, isExpression); + return element; + } + + function convertToObjectLiteralElement(element: EffectiveBindingOrAssignmentElement) { + if (isBindingElement(element)) { + if (element.dotDotDotToken) { + Debug.assertNode(element.name, isIdentifier); + return setOriginalNode(createSpreadAssignment(element.name, element), element); + } + if (element.propertyName) { + const expression = convertToExpressionTarget(element.name); + return setOriginalNode(createPropertyAssignment(element.propertyName, element.initializer ? createAssignment(expression, element.initializer) : expression, element), element); + } + Debug.assertNode(element.name, isIdentifier); + return setOriginalNode(createShorthandPropertyAssignment(element.name, element.initializer, element), element); + } + Debug.assertNode(element, isObjectLiteralElementLike); + return element; + } + + function convertToExpressionTarget(target: EffectiveBindingOrAssignmentTarget): Expression { + if (isBindingPattern(target)) { + switch (target.kind) { + case SyntaxKind.ArrayBindingPattern: + return setOriginalNode(createArrayLiteral(map(target.elements, convertToArrayLiteralElement), target), target); + case SyntaxKind.ObjectBindingPattern: + return setOriginalNode(createObjectLiteral(map(target.elements, convertToObjectLiteralElement), target), target); + } + return; + } + Debug.assertNode(target, isExpression); + return target; } /** Given value: o, propName: p, pattern: { a, b, ...p } from the original statement * `{ a, b, ...p } = o`, create `p = __rest(o, ["a", "b"]);`*/ - function createRestCall(value: Expression, elements: EffectiveBindingElement[], location: TextRange): Expression { + function createRestCall(value: Expression, elements: EffectiveBindingOrAssignmentElement[], location: TextRange): Expression { const propertyNames: LiteralExpression[] = []; for (let i = 0; i < elements.length - 1; i++) { if (isOmittedExpression(elements[i])) { diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index e4fb8a0aaf0..dd7498c4149 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -279,7 +279,7 @@ namespace ts { else if (node.transformFlags & TransformFlags.ContainsES2015 || (isInConstructorWithCapturedSuper && !isExpression(node))) { // we want to dive in this branch either if node has children with ES2015 specific syntax // or we are inside constructor that captures result of the super call so all returns without expression should be - // rewritten. Note: we skip expressions since returns should never appear there + // rewritten. Note: we skip expressions since returns should never appear there return visitEachChild(node, visitor, context); } else { @@ -861,7 +861,7 @@ namespace ts { } if (constructor) { - addDefaultValueAssignmentsIfNeeded(statements, constructor, visitor, /*convertObjectRest*/ false); + addDefaultValueAssignmentsIfNeeded(context, statements, constructor, visitor, /*convertObjectRest*/ false); addRestParameterIfNeeded(statements, constructor, hasSynthesizedSuper); Debug.assert(statementOffset >= 0, "statementOffset not initialized correctly!"); @@ -1328,16 +1328,10 @@ namespace ts { // If we are here it is most likely because our expression is a destructuring assignment. switch (node.expression.kind) { case SyntaxKind.ParenthesizedExpression: - return updateStatement(node, - visitParenthesizedExpression(node.expression, /*needsDestructuringValue*/ false) - ); - + return updateStatement(node, visitParenthesizedExpression(node.expression, /*needsDestructuringValue*/ false)); case SyntaxKind.BinaryExpression: - return updateStatement(node, - visitBinaryExpression(node.expression, /*needsDestructuringValue*/ false) - ); + return updateStatement(node, visitBinaryExpression(node.expression, /*needsDestructuringValue*/ false)); } - return visitEachChild(node, visitor, context); } @@ -1350,22 +1344,14 @@ namespace ts { */ function visitParenthesizedExpression(node: ParenthesizedExpression, needsDestructuringValue: boolean): ParenthesizedExpression { // If we are here it is most likely because our expression is a destructuring assignment. - if (needsDestructuringValue) { + if (!needsDestructuringValue) { switch (node.expression.kind) { case SyntaxKind.ParenthesizedExpression: - return createParen( - visitParenthesizedExpression(node.expression, /*needsDestructuringValue*/ true), - /*location*/ node - ); - + return updateParen(node, visitParenthesizedExpression(node.expression, /*needsDestructuringValue*/ false)); case SyntaxKind.BinaryExpression: - return createParen( - visitBinaryExpression(node.expression, /*needsDestructuringValue*/ true), - /*location*/ node - ); + return updateParen(node, visitBinaryExpression(node.expression, /*needsDestructuringValue*/ false)); } } - return visitEachChild(node, visitor, context); } @@ -1379,7 +1365,13 @@ namespace ts { function visitBinaryExpression(node: BinaryExpression, needsDestructuringValue: boolean): Expression { // If we are here it is because this is a destructuring assignment. Debug.assert(isDestructuringAssignment(node)); - return flattenDestructuringAssignment(context, node, needsDestructuringValue, hoistVariableDeclaration, visitor); + return flattenDestructuringToExpression( + context, + node, + needsDestructuringValue, + FlattenLevel.All, + /*createAssignmentCallback*/ undefined, + visitor); } function visitVariableStatement(node: VariableStatement): Statement { @@ -1391,7 +1383,14 @@ namespace ts { if (decl.initializer) { let assignment: Expression; if (isBindingPattern(decl.name)) { - assignment = flattenVariableDestructuringToExpression(decl, hoistVariableDeclaration, /*createAssignmentCallback*/ undefined, visitor); + assignment = flattenDestructuringToExpression( + context, + decl, + /*needsValue*/ false, + FlattenLevel.All, + /*createAssignmentCallback*/ undefined, + visitor + ); } else { assignment = createBinary(decl.name, SyntaxKind.EqualsToken, visitNode(decl.initializer, visitor, isExpression)); @@ -1544,8 +1543,16 @@ namespace ts { if (isBindingPattern(node.name)) { const recordTempVariablesInLine = !enclosingVariableStatement || !hasModifier(enclosingVariableStatement, ModifierFlags.Export); - return flattenVariableDestructuring(node, /*value*/ undefined, visitor, - recordTempVariablesInLine ? undefined : hoistVariableDeclaration); + debugger; + return flattenDestructuringToDeclarations( + context, + node, + /*value*/ undefined, + /*skipInitializer*/ false, + recordTempVariablesInLine, + FlattenLevel.All, + visitor + ); } return visitEachChild(node, visitor, context); @@ -2174,7 +2181,7 @@ namespace ts { const temp = createTempVariable(undefined); const newVariableDeclaration = createVariableDeclaration(temp, undefined, undefined, node.variableDeclaration); - const vars = flattenVariableDestructuring(node.variableDeclaration, temp, visitor); + const vars = flattenDestructuringToDeclarations(context, node.variableDeclaration, temp, /*skipInitializer*/ false, /*recordTempVariablesInLine*/ true, FlattenLevel.All, visitor); const list = createVariableDeclarationList(vars, /*location*/node.variableDeclaration, /*flags*/node.variableDeclaration.flags); const destructure = createVariableStatement(undefined, list); @@ -2261,7 +2268,7 @@ namespace ts { setEmitFlags(thisArg, EmitFlags.NoSubstitution); } let resultingCall: CallExpression | BinaryExpression; - if (node.transformFlags & TransformFlags.ContainsSpreadExpression) { + if (node.transformFlags & TransformFlags.ContainsSpread) { // [source] // f(...a, b) // x.m(...a, b) @@ -2323,7 +2330,7 @@ namespace ts { */ function visitNewExpression(node: NewExpression): LeftHandSideExpression { // We are here because we contain a SpreadElementExpression. - Debug.assert((node.transformFlags & TransformFlags.ContainsSpreadExpression) !== 0); + Debug.assert((node.transformFlags & TransformFlags.ContainsSpread) !== 0); // [source] // new C(...a) diff --git a/src/compiler/transformers/es2017.ts b/src/compiler/transformers/es2017.ts index 548609d676c..0990e9c454f 100644 --- a/src/compiler/transformers/es2017.ts +++ b/src/compiler/transformers/es2017.ts @@ -29,12 +29,6 @@ namespace ts { */ let enabledSubstitutions: ES2017SubstitutionFlags; - /** - * Keeps track of whether we are within any containing namespaces when performing - * just-in-time substitution while printing an expression identifier. - */ - let applicableSubstitutions: ES2017SubstitutionFlags; - /** * This keeps track of containers where `super` is valid, for use with * just-in-time substitution for `super` expressions inside of async methods. @@ -49,8 +43,6 @@ namespace ts { context.onEmitNode = onEmitNode; context.onSubstituteNode = onSubstituteNode; - let currentScope: SourceFile | Block | ModuleBlock | CaseBlock; - return transformSourceFile; function transformSourceFile(node: SourceFile) { @@ -64,13 +56,9 @@ namespace ts { } function visitor(node: Node): VisitResult { - if (node.transformFlags & TransformFlags.ES2017) { + if (node.transformFlags & TransformFlags.ContainsES2017) { return visitorWorker(node); } - else if (node.transformFlags & TransformFlags.ContainsES2017) { - return visitEachChild(node, visitor, context); - } - return node; } @@ -101,8 +89,7 @@ namespace ts { return visitArrowFunction(node); default: - Debug.failBadSyntaxKind(node); - return node; + return visitEachChild(node, visitor, context); } } @@ -133,28 +120,18 @@ namespace ts { * @param node The method node. */ function visitMethodDeclaration(node: MethodDeclaration) { - if (!isAsyncFunctionLike(node)) { - return node; - } - const method = createMethod( + return updateMethod( + node, /*decorators*/ undefined, visitNodes(node.modifiers, visitor, isModifier), - node.asteriskToken, node.name, /*typeParameters*/ undefined, - visitNodes(node.parameters, visitor, isParameter), + visitParameterList(node.parameters, visitor, context), /*type*/ undefined, - transformFunctionBody(node), - /*location*/ node + isAsyncFunctionLike(node) + ? transformAsyncFunctionBody(node) + : visitFunctionBody(node.body, visitor, context) ); - - // While we emit the source map for the node after skipping decorators and modifiers, - // we need to emit the comments for the original range. - setCommentRange(method, node); - setSourceMapRange(method, moveRangePastDecorators(node)); - setOriginalNode(method, node); - - return method; } /** @@ -166,23 +143,18 @@ namespace ts { * @param node The function node. */ function visitFunctionDeclaration(node: FunctionDeclaration): VisitResult { - if (!isAsyncFunctionLike(node)) { - return node; - } - const func = createFunctionDeclaration( + return updateFunctionDeclaration( + node, /*decorators*/ undefined, visitNodes(node.modifiers, visitor, isModifier), - node.asteriskToken, node.name, /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, - transformFunctionBody(node), - /*location*/ node + isAsyncFunctionLike(node) + ? transformAsyncFunctionBody(node) + : visitFunctionBody(node.body, visitor, context) ); - setOriginalNode(func, node); - - return func; } /** @@ -194,27 +166,20 @@ namespace ts { * @param node The function expression node. */ function visitFunctionExpression(node: FunctionExpression): Expression { - if (!isAsyncFunctionLike(node)) { - return node; - } if (nodeIsMissing(node.body)) { return createOmittedExpression(); } - - const func = createFunctionExpression( + return updateFunctionExpression( + node, /*modifiers*/ undefined, - node.asteriskToken, node.name, /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, - transformFunctionBody(node), - /*location*/ node + isAsyncFunctionLike(node) + ? transformAsyncFunctionBody(node) + : visitFunctionBody(node.body, visitor, context) ); - - setOriginalNode(func, node); - - return func; } /** @@ -223,45 +188,21 @@ namespace ts { * - The node is marked async */ function visitArrowFunction(node: ArrowFunction) { - if (!isAsyncFunctionLike(node)) { - return node; - } - const func = createArrowFunction( + return updateArrowFunction( + node, visitNodes(node.modifiers, visitor, isModifier), /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, - node.equalsGreaterThanToken, - transformConciseBody(node), - /*location*/ node + isAsyncFunctionLike(node) + ? transformAsyncFunctionBody(node) + : visitFunctionBody(node.body, visitor, context) ); - - setOriginalNode(func, node); - - return func; } - function transformFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody { - return transformAsyncFunctionBody(node); - } - - function transformConciseBody(node: ArrowFunction): ConciseBody { - return transformAsyncFunctionBody(node); - } - - function transformFunctionBodyWorker(body: Block, start = 0) { - const savedCurrentScope = currentScope; - currentScope = body; - startLexicalEnvironment(); - - const statements = visitNodes(body.statements, visitor, isStatement, start); - const visited = updateBlock(body, statements); - const declarations = endLexicalEnvironment(); - currentScope = savedCurrentScope; - return mergeFunctionBodyLexicalEnvironment(visited, declarations); - } - - function transformAsyncFunctionBody(node: FunctionLikeDeclaration): ConciseBody | FunctionBody { + function transformAsyncFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody; + function transformAsyncFunctionBody(node: ArrowFunction): ConciseBody; + function transformAsyncFunctionBody(node: FunctionLikeDeclaration): ConciseBody { const original = getOriginalNode(node, isFunctionLike); const nodeType = original.type; const promiseConstructor = languageVersion < ScriptTarget.ES2015 ? getPromiseConstructor(nodeType) : undefined; @@ -274,7 +215,6 @@ namespace ts { // passed to `__awaiter` is executed inside of the callback to the // promise constructor. - if (!isArrowFunction) { const statements: Statement[] = []; const statementOffset = addPrologueDirectives(statements, (node.body).statements, /*ensureUseStrict*/ false, visitor); @@ -289,6 +229,7 @@ namespace ts { ) ); + addRange(statements, endLexicalEnvironment()); const block = createBlock(statements, /*location*/ node.body, /*multiLine*/ true); // Minor optimization, emit `_super` helper to capture `super` access in an arrow. @@ -307,32 +248,32 @@ namespace ts { return block; } else { - return createAwaiterHelper( + const expression = createAwaiterHelper( currentSourceFileExternalHelpersModuleName, hasLexicalArguments, promiseConstructor, - transformConciseBodyWorker(node.body, /*forceBlockFunctionBody*/ true) + transformFunctionBodyWorker(node.body) ); + + const declarations = endLexicalEnvironment(); + if (some(declarations)) { + const block = convertToFunctionBody(expression); + return updateBlock(block, createNodeArray(concatenate(block.statements, declarations), block.statements)); + } + + return expression; } } - function transformConciseBodyWorker(body: Block | Expression, forceBlockFunctionBody: boolean) { + function transformFunctionBodyWorker(body: ConciseBody, start?: number) { if (isBlock(body)) { - return transformFunctionBodyWorker(body); + return updateBlock(body, visitLexicalEnvironment(body.statements, visitor, context, start)); } else { startLexicalEnvironment(); - const visited: Expression | Block = visitNode(body, visitor, isConciseBody); + const visited = convertToFunctionBody(visitNode(body, visitor, isConciseBody)); const declarations = endLexicalEnvironment(); - const merged = mergeFunctionBodyLexicalEnvironment(visited, declarations); - if (forceBlockFunctionBody && !isBlock(merged)) { - return createBlock([ - createReturn(merged) - ]); - } - else { - return merged; - } + return updateBlock(visited, createNodeArray(concatenate(visited.statements, declarations), visited.statements)); } } @@ -452,18 +393,17 @@ namespace ts { * @param emit A callback used to emit the node in the printer. */ function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void { - const savedApplicableSubstitutions = applicableSubstitutions; - const savedCurrentSuperContainer = currentSuperContainer; // If we need to support substitutions for `super` in an async method, // we should track it here. if (enabledSubstitutions & ES2017SubstitutionFlags.AsyncMethodsWithSuper && isSuperContainer(node)) { + const savedCurrentSuperContainer = currentSuperContainer; currentSuperContainer = node; + previousOnEmitNode(emitContext, node, emitCallback); + currentSuperContainer = savedCurrentSuperContainer; + } + else { + previousOnEmitNode(emitContext, node, emitCallback); } - - previousOnEmitNode(emitContext, node, emitCallback); - - applicableSubstitutions = savedApplicableSubstitutions; - currentSuperContainer = savedCurrentSuperContainer; } /** diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 9013fabf584..a52ee9b1a24 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -4,9 +4,6 @@ /*@internal*/ namespace ts { export function transformESNext(context: TransformationContext) { - const { - hoistVariableDeclaration, - } = context; let currentSourceFile: SourceFile; return transformSourceFile; @@ -20,7 +17,7 @@ namespace ts { return visitorWorker(node); } else if (node.transformFlags & TransformFlags.ContainsESNext) { - return visitEachChild(node, visitor, context); + return visitNodeContainingESNext(node); } else { return node; @@ -32,7 +29,7 @@ namespace ts { case SyntaxKind.ObjectLiteralExpression: return visitObjectLiteralExpression(node as ObjectLiteralExpression); case SyntaxKind.BinaryExpression: - return visitBinaryExpression(node as BinaryExpression); + return visitBinaryExpression(node as BinaryExpression, /*needsDestructuringValue*/ true); case SyntaxKind.VariableDeclaration: return visitVariableDeclaration(node as VariableDeclaration); case SyntaxKind.ForOfStatement: @@ -54,6 +51,16 @@ namespace ts { } } + function visitNodeContainingESNext(node: Node) { + switch (node.kind) { + case SyntaxKind.ExpressionStatement: + return visitExpressionStatement(node as ExpressionStatement); + case SyntaxKind.ParenthesizedExpression: + return visitParenthesizedExpression(node as ParenthesizedExpression, /*needsDestructuringValue*/ true); + } + return visitEachChild(node, visitor, context); + } + function chunkObjectLiteralElements(elements: ObjectLiteralElement[]): Expression[] { let chunkObject: (ShorthandPropertyAssignment | PropertyAssignment)[]; const objects: Expression[] = []; @@ -99,14 +106,43 @@ namespace ts { return createCall(createIdentifier("__assign"), undefined, objects); } + function visitExpressionStatement(node: ExpressionStatement): ExpressionStatement { + switch (node.expression.kind) { + case SyntaxKind.ParenthesizedExpression: + return updateStatement(node, visitParenthesizedExpression(node.expression, /*needsDestructuringValue*/ false)); + case SyntaxKind.BinaryExpression: + return updateStatement(node, visitBinaryExpression(node.expression, /*needsDestructuringValue*/ false)); + } + return visitEachChild(node, visitor, context); + } + + function visitParenthesizedExpression(node: ParenthesizedExpression, needsDestructuringValue: boolean): ParenthesizedExpression { + if (!needsDestructuringValue) { + switch (node.expression.kind) { + case SyntaxKind.ParenthesizedExpression: + return updateParen(node, visitParenthesizedExpression(node.expression, /*needsDestructuringValue*/ false)); + case SyntaxKind.BinaryExpression: + return updateParen(node, visitBinaryExpression(node.expression, /*needsDestructuringValue*/ false)); + } + } + return visitEachChild(node, visitor, context); + } + /** * Visits a BinaryExpression that contains a destructuring assignment. * * @param node A BinaryExpression node. */ - function visitBinaryExpression(node: BinaryExpression): Expression { + function visitBinaryExpression(node: BinaryExpression, needsDestructuringValue: boolean): Expression { if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.ContainsESNext) { - return flattenDestructuringAssignment(context, node, /*needsDestructuringValue*/ true, hoistVariableDeclaration, visitor, /*transformRest*/ true); + return flattenDestructuringToExpression( + context, + node, + needsDestructuringValue, + FlattenLevel.ObjectRest, + /*createAssignmentCallback*/ undefined, + visitor + ); } return visitEachChild(node, visitor, context); @@ -120,10 +156,8 @@ namespace ts { function visitVariableDeclaration(node: VariableDeclaration): VisitResult { // If we are here it is because the name contains a binding pattern with a rest somewhere in it. if (isBindingPattern(node.name) && node.name.transformFlags & TransformFlags.AssertESNext) { - const result = flattenVariableDestructuring(node, /*value*/ undefined, visitor, /*recordTempVariable*/ undefined, /*transformRest*/ true); - return result; + return flattenDestructuringToDeclarations(context, node, /*boundValue*/ undefined, /*skipInitializer*/ false, /*recordTempVariablesInLine*/ true, FlattenLevel.ObjectRest, visitor); } - return visitEachChild(node, visitor, context); } @@ -168,14 +202,14 @@ namespace ts { const declaration = firstOrUndefined(initializer.declarations); return declaration && declaration.name && declaration.name.kind === SyntaxKind.ObjectBindingPattern && - !!(declaration.name.transformFlags & TransformFlags.ContainsSpreadExpression); + !!(declaration.name.transformFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)); } return false; } function isRestAssignment(initializer: ForInitializer) { return initializer.kind === SyntaxKind.ObjectLiteralExpression && - initializer.transformFlags & TransformFlags.ContainsSpreadExpression; + initializer.transformFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest); } function visitParameter(node: ParameterDeclaration): ParameterDeclaration { @@ -204,7 +238,7 @@ namespace ts { function isObjectRestParameter(node: ParameterDeclaration) { return node.name && node.name.kind === SyntaxKind.ObjectBindingPattern && - !!(node.name.transformFlags & TransformFlags.ContainsSpreadExpression); + !!(node.name.transformFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)); } function visitFunctionDeclaration(node: FunctionDeclaration): FunctionDeclaration { diff --git a/src/compiler/transformers/jsx.ts b/src/compiler/transformers/jsx.ts index ba762cc5f12..8bc09ea45b2 100644 --- a/src/compiler/transformers/jsx.ts +++ b/src/compiler/transformers/jsx.ts @@ -27,12 +27,9 @@ namespace ts { } function visitor(node: Node): VisitResult { - if (node.transformFlags & TransformFlags.Jsx) { + if (node.transformFlags & TransformFlags.ContainsJsx) { return visitorWorker(node); } - else if (node.transformFlags & TransformFlags.ContainsJsx) { - return visitEachChild(node, visitor, context); - } else { return node; } @@ -50,8 +47,7 @@ namespace ts { return visitJsxExpression(node); default: - Debug.failBadSyntaxKind(node); - return undefined; + return visitEachChild(node, visitor, context); } } diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index 87d02b44025..bb17b99e5c6 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -19,8 +19,7 @@ namespace ts { const { startLexicalEnvironment, - endLexicalEnvironment, - hoistVariableDeclaration, + endLexicalEnvironment } = context; const compilerOptions = context.getCompilerOptions(); @@ -757,10 +756,13 @@ namespace ts { */ function transformInitializedVariable(node: VariableDeclaration): Expression { if (isBindingPattern(node.name)) { - return flattenVariableDestructuringToExpression( + return flattenDestructuringToExpression( + context, node, - hoistVariableDeclaration, - createExportExpression + /*needsValue*/ false, + FlattenLevel.All, + createExportExpression, + /*visitor*/ undefined ); } else { diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index 0524b9354d2..1ed1f82d506 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -808,7 +808,7 @@ namespace ts { function transformInitializedVariable(node: VariableDeclaration, isExportedDeclaration: boolean): Expression { const createAssignment = isExportedDeclaration ? createExportedVariableAssignment : createNonExportedVariableAssignment; return isBindingPattern(node.name) - ? flattenVariableDestructuringToExpression(node, hoistVariableDeclaration, createAssignment, destructuringVisitor) + ? flattenDestructuringToExpression(context, node, /*needsValue*/ false, FlattenLevel.All, createAssignment, destructuringVisitor) : createAssignment(node.name, visitNode(node.initializer, destructuringVisitor, isExpression)); } @@ -1459,7 +1459,13 @@ namespace ts { */ function visitDestructuringAssignment(node: DestructuringAssignment): VisitResult { if (hasExportedReferenceInDestructuringTarget(node.left)) { - return flattenDestructuringAssignment(context, node, /*needsValue*/ true, hoistVariableDeclaration, destructuringVisitor); + return flattenDestructuringToExpression( + context, + node, + /*needsValue*/ true, + FlattenLevel.All, + /*createAssignmentCallback*/ undefined, + destructuringVisitor); } return visitEachChild(node, destructuringVisitor, context); diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 89fa039100a..118b170b6a4 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -2353,9 +2353,11 @@ namespace ts { function transformInitializedVariable(node: VariableDeclaration): Expression { const name = node.name; if (isBindingPattern(name)) { - return flattenVariableDestructuringToExpression( + return flattenDestructuringToExpression( + context, node, - hoistVariableDeclaration, + /*needsValue*/ false, + FlattenLevel.All, createNamespaceExportExpression, visitor ); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e8018083783..e0ba546fb96 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -506,6 +506,7 @@ namespace ts { export interface NodeArray extends Array, TextRange { hasTrailingComma?: boolean; + /* @internal */ transformFlags?: TransformFlags; } export interface Token extends Node { @@ -3495,45 +3496,46 @@ namespace ts { // - Flags used to indicate that a node or subtree contains syntax that requires transformation. TypeScript = 1 << 0, ContainsTypeScript = 1 << 1, - Jsx = 1 << 2, - ContainsJsx = 1 << 3, - ESNext = 1 << 4, - ContainsESNext = 1 << 5, - ES2017 = 1 << 6, - ContainsES2017 = 1 << 7, - ES2016 = 1 << 8, - ContainsES2016 = 1 << 9, - ES2015 = 1 << 10, - ContainsES2015 = 1 << 11, - Generator = 1 << 12, - ContainsGenerator = 1 << 13, - DestructuringAssignment = 1 << 14, - ContainsDestructuringAssignment = 1 << 15, + ContainsJsx = 1 << 2, + ESNext = 1 << 3, + ContainsESNext = 1 << 4, + ContainsES2017 = 1 << 5, + ES2016 = 1 << 6, + ContainsES2016 = 1 << 7, + ES2015 = 1 << 8, + ContainsES2015 = 1 << 9, + Generator = 1 << 10, + ContainsGenerator = 1 << 11, + DestructuringAssignment = 1 << 12, + ContainsDestructuringAssignment = 1 << 13, // Markers // - Flags used to indicate that a subtree contains a specific transformation. - ContainsDecorators = 1 << 16, - ContainsPropertyInitializer = 1 << 17, - ContainsLexicalThis = 1 << 18, - ContainsCapturedLexicalThis = 1 << 19, - ContainsLexicalThisInComputedPropertyName = 1 << 20, - ContainsDefaultValueAssignments = 1 << 21, - ContainsParameterPropertyAssignments = 1 << 22, - ContainsSpreadExpression = 1 << 23, - ContainsComputedPropertyName = 1 << 24, - ContainsBlockScopedBinding = 1 << 25, - ContainsBindingPattern = 1 << 26, - ContainsYield = 1 << 27, - ContainsHoistedDeclarationOrCompletion = 1 << 28, + ContainsDecorators = 1 << 14, + ContainsPropertyInitializer = 1 << 15, + ContainsLexicalThis = 1 << 16, + ContainsCapturedLexicalThis = 1 << 17, + ContainsLexicalThisInComputedPropertyName = 1 << 18, + ContainsDefaultValueAssignments = 1 << 19, + ContainsParameterPropertyAssignments = 1 << 20, + ContainsSpread = 1 << 21, + ContainsRest = ContainsSpread, + ContainsObjectSpread = 1 << 22, + ContainsObjectRest = ContainsObjectSpread, + ContainsComputedPropertyName = 1 << 23, + ContainsBlockScopedBinding = 1 << 24, + ContainsBindingPattern = 1 << 25, + ContainsYield = 1 << 26, + ContainsHoistedDeclarationOrCompletion = 1 << 27, HasComputedFlags = 1 << 29, // Transform flags have been computed. // Assertions // - Bitmasks that are used to assert facts about the syntax of a node and its subtree. AssertTypeScript = TypeScript | ContainsTypeScript, - AssertJsx = Jsx | ContainsJsx, + AssertJsx = ContainsJsx, AssertESNext = ESNext | ContainsESNext, - AssertES2017 = ES2017 | ContainsES2017, + AssertES2017 = ContainsES2017, AssertES2016 = ES2016 | ContainsES2016, AssertES2015 = ES2015 | ContainsES2015, AssertGenerator = Generator | ContainsGenerator, @@ -3542,18 +3544,20 @@ namespace ts { // Scope Exclusions // - Bitmasks that exclude flags from propagating out of a specific context // into the subtree flags of their container. - NodeExcludes = TypeScript | Jsx | ESNext | ES2017 | ES2016 | ES2015 | DestructuringAssignment | Generator | HasComputedFlags, - ArrowFunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion, - FunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion, - ConstructorExcludes = NodeExcludes | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion, - MethodOrAccessorExcludes = NodeExcludes | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion, + NodeExcludes = TypeScript | ESNext | ES2016 | ES2015 | DestructuringAssignment | Generator | HasComputedFlags, + ArrowFunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRest, + FunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRest, + ConstructorExcludes = NodeExcludes | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRest, + MethodOrAccessorExcludes = NodeExcludes | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRest, ClassExcludes = NodeExcludes | ContainsDecorators | ContainsPropertyInitializer | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsComputedPropertyName | ContainsParameterPropertyAssignments | ContainsLexicalThisInComputedPropertyName, ModuleExcludes = NodeExcludes | ContainsDecorators | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsHoistedDeclarationOrCompletion, TypeExcludes = ~ContainsTypeScript, - ObjectLiteralExcludes = NodeExcludes | ContainsDecorators | ContainsComputedPropertyName | ContainsLexicalThisInComputedPropertyName, - ArrayLiteralOrCallOrNewExcludes = NodeExcludes | ContainsSpreadExpression, - VariableDeclarationListExcludes = NodeExcludes | ContainsBindingPattern, - ParameterExcludes = NodeExcludes | ContainsBindingPattern, + ObjectLiteralExcludes = NodeExcludes | ContainsDecorators | ContainsComputedPropertyName | ContainsLexicalThisInComputedPropertyName | ContainsObjectSpread, + ArrayLiteralOrCallOrNewExcludes = NodeExcludes | ContainsSpread, + VariableDeclarationListExcludes = NodeExcludes | ContainsBindingPattern | ContainsObjectSpread, + ParameterExcludes = NodeExcludes, + CatchClauseExcludes = NodeExcludes | ContainsObjectSpread, + BindingPatternExcludes = NodeExcludes | ContainsSpread, // Masks // - Additional bitmasks @@ -3622,7 +3626,6 @@ namespace ts { endLexicalEnvironment(): Statement[]; } - export interface TextSpan { start: number; length: number; diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index ebb3ec01ed3..825e0b45e45 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -99,20 +99,26 @@ namespace ts { return node ? f(initial, node) : initial; } + function reduceNodeArray(nodes: Node[], f: (memo: T, nodes: Node[]) => T, initial: T) { + return nodes ? f(initial, nodes) : initial; + } + /** * Similar to `reduceLeft`, performs a reduction against each child of a node. * NOTE: Unlike `forEachChild`, this does *not* visit every node. Only nodes added to the * `nodeEdgeTraversalMap` above will be visited. * * @param node The node containing the children to reduce. - * @param f The callback function * @param initial The initial value to supply to the reduction. + * @param f The callback function */ - export function reduceEachChild(node: Node, f: (memo: T, node: Node) => T, initial: T): T { + export function reduceEachChild(node: Node, initial: T, cbNode: (memo: T, node: Node) => T, cbNodeArray?: (memo: T, nodes: Node[]) => T): T { if (node === undefined) { return initial; } + const reduceNodes: (nodes: Node[], f: (memo: T, node: Node | Node[]) => T, initial: T) => T = cbNodeArray ? reduceNodeArray : reduceLeft; + const cbNodes = cbNodeArray || cbNode; const kind = node.kind; // No need to visit nodes with no children. @@ -138,127 +144,127 @@ namespace ts { // Names case SyntaxKind.ComputedPropertyName: - result = reduceNode((node).expression, f, result); + result = reduceNode((node).expression, cbNode, result); break; // Signature elements case SyntaxKind.Parameter: - result = reduceLeft((node).decorators, f, result); - result = reduceLeft((node).modifiers, f, result); - result = reduceNode((node).name, f, result); - result = reduceNode((node).type, f, result); - result = reduceNode((node).initializer, f, result); + result = reduceNodes((node).decorators, cbNodes, result); + result = reduceNodes((node).modifiers, cbNodes, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNode((node).type, cbNode, result); + result = reduceNode((node).initializer, cbNode, result); break; case SyntaxKind.Decorator: - result = reduceNode((node).expression, f, result); + result = reduceNode((node).expression, cbNode, result); break; // Type member case SyntaxKind.PropertyDeclaration: - result = reduceLeft((node).decorators, f, result); - result = reduceLeft((node).modifiers, f, result); - result = reduceNode((node).name, f, result); - result = reduceNode((node).type, f, result); - result = reduceNode((node).initializer, f, result); + result = reduceNodes((node).decorators, cbNodes, result); + result = reduceNodes((node).modifiers, cbNodes, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNode((node).type, cbNode, result); + result = reduceNode((node).initializer, cbNode, result); break; case SyntaxKind.MethodDeclaration: - result = reduceLeft((node).decorators, f, result); - result = reduceLeft((node).modifiers, f, result); - result = reduceNode((node).name, f, result); - result = reduceLeft((node).typeParameters, f, result); - result = reduceLeft((node).parameters, f, result); - result = reduceNode((node).type, f, result); - result = reduceNode((node).body, f, result); + result = reduceNodes((node).decorators, cbNodes, result); + result = reduceNodes((node).modifiers, cbNodes, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNodes((node).typeParameters, cbNodes, result); + result = reduceNodes((node).parameters, cbNodes, result); + result = reduceNode((node).type, cbNode, result); + result = reduceNode((node).body, cbNode, result); break; case SyntaxKind.Constructor: - result = reduceLeft((node).modifiers, f, result); - result = reduceLeft((node).parameters, f, result); - result = reduceNode((node).body, f, result); + result = reduceNodes((node).modifiers, cbNodes, result); + result = reduceNodes((node).parameters, cbNodes, result); + result = reduceNode((node).body, cbNode, result); break; case SyntaxKind.GetAccessor: - result = reduceLeft((node).decorators, f, result); - result = reduceLeft((node).modifiers, f, result); - result = reduceNode((node).name, f, result); - result = reduceLeft((node).parameters, f, result); - result = reduceNode((node).type, f, result); - result = reduceNode((node).body, f, result); + result = reduceNodes((node).decorators, cbNodes, result); + result = reduceNodes((node).modifiers, cbNodes, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNodes((node).parameters, cbNodes, result); + result = reduceNode((node).type, cbNode, result); + result = reduceNode((node).body, cbNode, result); break; case SyntaxKind.SetAccessor: - result = reduceLeft((node).decorators, f, result); - result = reduceLeft((node).modifiers, f, result); - result = reduceNode((node).name, f, result); - result = reduceLeft((node).parameters, f, result); - result = reduceNode((node).body, f, result); + result = reduceNodes((node).decorators, cbNodes, result); + result = reduceNodes((node).modifiers, cbNodes, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNodes((node).parameters, cbNodes, result); + result = reduceNode((node).body, cbNode, result); break; // Binding patterns case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: - result = reduceLeft((node).elements, f, result); + result = reduceNodes((node).elements, cbNodes, result); break; case SyntaxKind.BindingElement: - result = reduceNode((node).propertyName, f, result); - result = reduceNode((node).name, f, result); - result = reduceNode((node).initializer, f, result); + result = reduceNode((node).propertyName, cbNode, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNode((node).initializer, cbNode, result); break; // Expression case SyntaxKind.ArrayLiteralExpression: - result = reduceLeft((node).elements, f, result); + result = reduceNodes((node).elements, cbNodes, result); break; case SyntaxKind.ObjectLiteralExpression: - result = reduceLeft((node).properties, f, result); + result = reduceNodes((node).properties, cbNodes, result); break; case SyntaxKind.PropertyAccessExpression: - result = reduceNode((node).expression, f, result); - result = reduceNode((node).name, f, result); + result = reduceNode((node).expression, cbNode, result); + result = reduceNode((node).name, cbNode, result); break; case SyntaxKind.ElementAccessExpression: - result = reduceNode((node).expression, f, result); - result = reduceNode((node).argumentExpression, f, result); + result = reduceNode((node).expression, cbNode, result); + result = reduceNode((node).argumentExpression, cbNode, result); break; case SyntaxKind.CallExpression: - result = reduceNode((node).expression, f, result); - result = reduceLeft((node).typeArguments, f, result); - result = reduceLeft((node).arguments, f, result); + result = reduceNode((node).expression, cbNode, result); + result = reduceNodes((node).typeArguments, cbNodes, result); + result = reduceNodes((node).arguments, cbNodes, result); break; case SyntaxKind.NewExpression: - result = reduceNode((node).expression, f, result); - result = reduceLeft((node).typeArguments, f, result); - result = reduceLeft((node).arguments, f, result); + result = reduceNode((node).expression, cbNode, result); + result = reduceNodes((node).typeArguments, cbNodes, result); + result = reduceNodes((node).arguments, cbNodes, result); break; case SyntaxKind.TaggedTemplateExpression: - result = reduceNode((node).tag, f, result); - result = reduceNode((node).template, f, result); + result = reduceNode((node).tag, cbNode, result); + result = reduceNode((node).template, cbNode, result); break; case SyntaxKind.FunctionExpression: - result = reduceLeft((node).modifiers, f, result); - result = reduceNode((node).name, f, result); - result = reduceLeft((node).typeParameters, f, result); - result = reduceLeft((node).parameters, f, result); - result = reduceNode((node).type, f, result); - result = reduceNode((node).body, f, result); + result = reduceNodes((node).modifiers, cbNodes, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNodes((node).typeParameters, cbNodes, result); + result = reduceNodes((node).parameters, cbNodes, result); + result = reduceNode((node).type, cbNode, result); + result = reduceNode((node).body, cbNode, result); break; case SyntaxKind.ArrowFunction: - result = reduceLeft((node).modifiers, f, result); - result = reduceLeft((node).typeParameters, f, result); - result = reduceLeft((node).parameters, f, result); - result = reduceNode((node).type, f, result); - result = reduceNode((node).body, f, result); + result = reduceNodes((node).modifiers, cbNodes, result); + result = reduceNodes((node).typeParameters, cbNodes, result); + result = reduceNodes((node).parameters, cbNodes, result); + result = reduceNode((node).type, cbNode, result); + result = reduceNode((node).body, cbNode, result); break; case SyntaxKind.ParenthesizedExpression: @@ -269,258 +275,258 @@ namespace ts { case SyntaxKind.YieldExpression: case SyntaxKind.SpreadElement: case SyntaxKind.NonNullExpression: - result = reduceNode((node).expression, f, result); + result = reduceNode((node).expression, cbNode, result); break; case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: - result = reduceNode((node).operand, f, result); + result = reduceNode((node).operand, cbNode, result); break; case SyntaxKind.BinaryExpression: - result = reduceNode((node).left, f, result); - result = reduceNode((node).right, f, result); + result = reduceNode((node).left, cbNode, result); + result = reduceNode((node).right, cbNode, result); break; case SyntaxKind.ConditionalExpression: - result = reduceNode((node).condition, f, result); - result = reduceNode((node).whenTrue, f, result); - result = reduceNode((node).whenFalse, f, result); + result = reduceNode((node).condition, cbNode, result); + result = reduceNode((node).whenTrue, cbNode, result); + result = reduceNode((node).whenFalse, cbNode, result); break; case SyntaxKind.TemplateExpression: - result = reduceNode((node).head, f, result); - result = reduceLeft((node).templateSpans, f, result); + result = reduceNode((node).head, cbNode, result); + result = reduceNodes((node).templateSpans, cbNodes, result); break; case SyntaxKind.ClassExpression: - result = reduceLeft((node).modifiers, f, result); - result = reduceNode((node).name, f, result); - result = reduceLeft((node).typeParameters, f, result); - result = reduceLeft((node).heritageClauses, f, result); - result = reduceLeft((node).members, f, result); + result = reduceNodes((node).modifiers, cbNodes, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNodes((node).typeParameters, cbNodes, result); + result = reduceNodes((node).heritageClauses, cbNodes, result); + result = reduceNodes((node).members, cbNodes, result); break; case SyntaxKind.ExpressionWithTypeArguments: - result = reduceNode((node).expression, f, result); - result = reduceLeft((node).typeArguments, f, result); + result = reduceNode((node).expression, cbNode, result); + result = reduceNodes((node).typeArguments, cbNodes, result); break; // Misc case SyntaxKind.TemplateSpan: - result = reduceNode((node).expression, f, result); - result = reduceNode((node).literal, f, result); + result = reduceNode((node).expression, cbNode, result); + result = reduceNode((node).literal, cbNode, result); break; // Element case SyntaxKind.Block: - result = reduceLeft((node).statements, f, result); + result = reduceNodes((node).statements, cbNodes, result); break; case SyntaxKind.VariableStatement: - result = reduceLeft((node).modifiers, f, result); - result = reduceNode((node).declarationList, f, result); + result = reduceNodes((node).modifiers, cbNodes, result); + result = reduceNode((node).declarationList, cbNode, result); break; case SyntaxKind.ExpressionStatement: - result = reduceNode((node).expression, f, result); + result = reduceNode((node).expression, cbNode, result); break; case SyntaxKind.IfStatement: - result = reduceNode((node).expression, f, result); - result = reduceNode((node).thenStatement, f, result); - result = reduceNode((node).elseStatement, f, result); + result = reduceNode((node).expression, cbNode, result); + result = reduceNode((node).thenStatement, cbNode, result); + result = reduceNode((node).elseStatement, cbNode, result); break; case SyntaxKind.DoStatement: - result = reduceNode((node).statement, f, result); - result = reduceNode((node).expression, f, result); + result = reduceNode((node).statement, cbNode, result); + result = reduceNode((node).expression, cbNode, result); break; case SyntaxKind.WhileStatement: case SyntaxKind.WithStatement: - result = reduceNode((node).expression, f, result); - result = reduceNode((node).statement, f, result); + result = reduceNode((node).expression, cbNode, result); + result = reduceNode((node).statement, cbNode, result); break; case SyntaxKind.ForStatement: - result = reduceNode((node).initializer, f, result); - result = reduceNode((node).condition, f, result); - result = reduceNode((node).incrementor, f, result); - result = reduceNode((node).statement, f, result); + result = reduceNode((node).initializer, cbNode, result); + result = reduceNode((node).condition, cbNode, result); + result = reduceNode((node).incrementor, cbNode, result); + result = reduceNode((node).statement, cbNode, result); break; case SyntaxKind.ForInStatement: case SyntaxKind.ForOfStatement: - result = reduceNode((node).initializer, f, result); - result = reduceNode((node).expression, f, result); - result = reduceNode((node).statement, f, result); + result = reduceNode((node).initializer, cbNode, result); + result = reduceNode((node).expression, cbNode, result); + result = reduceNode((node).statement, cbNode, result); break; case SyntaxKind.ReturnStatement: case SyntaxKind.ThrowStatement: - result = reduceNode((node).expression, f, result); + result = reduceNode((node).expression, cbNode, result); break; case SyntaxKind.SwitchStatement: - result = reduceNode((node).expression, f, result); - result = reduceNode((node).caseBlock, f, result); + result = reduceNode((node).expression, cbNode, result); + result = reduceNode((node).caseBlock, cbNode, result); break; case SyntaxKind.LabeledStatement: - result = reduceNode((node).label, f, result); - result = reduceNode((node).statement, f, result); + result = reduceNode((node).label, cbNode, result); + result = reduceNode((node).statement, cbNode, result); break; case SyntaxKind.TryStatement: - result = reduceNode((node).tryBlock, f, result); - result = reduceNode((node).catchClause, f, result); - result = reduceNode((node).finallyBlock, f, result); + result = reduceNode((node).tryBlock, cbNode, result); + result = reduceNode((node).catchClause, cbNode, result); + result = reduceNode((node).finallyBlock, cbNode, result); break; case SyntaxKind.VariableDeclaration: - result = reduceNode((node).name, f, result); - result = reduceNode((node).type, f, result); - result = reduceNode((node).initializer, f, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNode((node).type, cbNode, result); + result = reduceNode((node).initializer, cbNode, result); break; case SyntaxKind.VariableDeclarationList: - result = reduceLeft((node).declarations, f, result); + result = reduceNodes((node).declarations, cbNodes, result); break; case SyntaxKind.FunctionDeclaration: - result = reduceLeft((node).decorators, f, result); - result = reduceLeft((node).modifiers, f, result); - result = reduceNode((node).name, f, result); - result = reduceLeft((node).typeParameters, f, result); - result = reduceLeft((node).parameters, f, result); - result = reduceNode((node).type, f, result); - result = reduceNode((node).body, f, result); + result = reduceNodes((node).decorators, cbNodes, result); + result = reduceNodes((node).modifiers, cbNodes, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNodes((node).typeParameters, cbNodes, result); + result = reduceNodes((node).parameters, cbNodes, result); + result = reduceNode((node).type, cbNode, result); + result = reduceNode((node).body, cbNode, result); break; case SyntaxKind.ClassDeclaration: - result = reduceLeft((node).decorators, f, result); - result = reduceLeft((node).modifiers, f, result); - result = reduceNode((node).name, f, result); - result = reduceLeft((node).typeParameters, f, result); - result = reduceLeft((node).heritageClauses, f, result); - result = reduceLeft((node).members, f, result); + result = reduceNodes((node).decorators, cbNodes, result); + result = reduceNodes((node).modifiers, cbNodes, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNodes((node).typeParameters, cbNodes, result); + result = reduceNodes((node).heritageClauses, cbNodes, result); + result = reduceNodes((node).members, cbNodes, result); break; case SyntaxKind.CaseBlock: - result = reduceLeft((node).clauses, f, result); + result = reduceNodes((node).clauses, cbNodes, result); break; case SyntaxKind.ImportDeclaration: - result = reduceLeft((node).decorators, f, result); - result = reduceLeft((node).modifiers, f, result); - result = reduceNode((node).importClause, f, result); - result = reduceNode((node).moduleSpecifier, f, result); + result = reduceNodes((node).decorators, cbNodes, result); + result = reduceNodes((node).modifiers, cbNodes, result); + result = reduceNode((node).importClause, cbNode, result); + result = reduceNode((node).moduleSpecifier, cbNode, result); break; case SyntaxKind.ImportClause: - result = reduceNode((node).name, f, result); - result = reduceNode((node).namedBindings, f, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNode((node).namedBindings, cbNode, result); break; case SyntaxKind.NamespaceImport: - result = reduceNode((node).name, f, result); + result = reduceNode((node).name, cbNode, result); break; case SyntaxKind.NamedImports: case SyntaxKind.NamedExports: - result = reduceLeft((node).elements, f, result); + result = reduceNodes((node).elements, cbNodes, result); break; case SyntaxKind.ImportSpecifier: case SyntaxKind.ExportSpecifier: - result = reduceNode((node).propertyName, f, result); - result = reduceNode((node).name, f, result); + result = reduceNode((node).propertyName, cbNode, result); + result = reduceNode((node).name, cbNode, result); break; case SyntaxKind.ExportAssignment: - result = reduceLeft((node).decorators, f, result); - result = reduceLeft((node).modifiers, f, result); - result = reduceNode((node).expression, f, result); + result = reduceLeft((node).decorators, cbNode, result); + result = reduceLeft((node).modifiers, cbNode, result); + result = reduceNode((node).expression, cbNode, result); break; case SyntaxKind.ExportDeclaration: - result = reduceLeft((node).decorators, f, result); - result = reduceLeft((node).modifiers, f, result); - result = reduceNode((node).exportClause, f, result); - result = reduceNode((node).moduleSpecifier, f, result); + result = reduceLeft((node).decorators, cbNode, result); + result = reduceLeft((node).modifiers, cbNode, result); + result = reduceNode((node).exportClause, cbNode, result); + result = reduceNode((node).moduleSpecifier, cbNode, result); break; // JSX case SyntaxKind.JsxElement: - result = reduceNode((node).openingElement, f, result); - result = reduceLeft((node).children, f, result); - result = reduceNode((node).closingElement, f, result); + result = reduceNode((node).openingElement, cbNode, result); + result = reduceLeft((node).children, cbNode, result); + result = reduceNode((node).closingElement, cbNode, result); break; case SyntaxKind.JsxSelfClosingElement: case SyntaxKind.JsxOpeningElement: - result = reduceNode((node).tagName, f, result); - result = reduceLeft((node).attributes, f, result); + result = reduceNode((node).tagName, cbNode, result); + result = reduceNodes((node).attributes, cbNodes, result); break; case SyntaxKind.JsxClosingElement: - result = reduceNode((node).tagName, f, result); + result = reduceNode((node).tagName, cbNode, result); break; case SyntaxKind.JsxAttribute: - result = reduceNode((node).name, f, result); - result = reduceNode((node).initializer, f, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNode((node).initializer, cbNode, result); break; case SyntaxKind.JsxSpreadAttribute: - result = reduceNode((node).expression, f, result); + result = reduceNode((node).expression, cbNode, result); break; case SyntaxKind.JsxExpression: - result = reduceNode((node).expression, f, result); + result = reduceNode((node).expression, cbNode, result); break; // Clauses case SyntaxKind.CaseClause: - result = reduceNode((node).expression, f, result); + result = reduceNode((node).expression, cbNode, result); // fall-through case SyntaxKind.DefaultClause: - result = reduceLeft((node).statements, f, result); + result = reduceNodes((node).statements, cbNodes, result); break; case SyntaxKind.HeritageClause: - result = reduceLeft((node).types, f, result); + result = reduceNodes((node).types, cbNodes, result); break; case SyntaxKind.CatchClause: - result = reduceNode((node).variableDeclaration, f, result); - result = reduceNode((node).block, f, result); + result = reduceNode((node).variableDeclaration, cbNode, result); + result = reduceNode((node).block, cbNode, result); break; // Property assignments case SyntaxKind.PropertyAssignment: - result = reduceNode((node).name, f, result); - result = reduceNode((node).initializer, f, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNode((node).initializer, cbNode, result); break; case SyntaxKind.ShorthandPropertyAssignment: - result = reduceNode((node).name, f, result); - result = reduceNode((node).objectAssignmentInitializer, f, result); + result = reduceNode((node).name, cbNode, result); + result = reduceNode((node).objectAssignmentInitializer, cbNode, result); break; case SyntaxKind.SpreadAssignment: - result = reduceNode((node as SpreadAssignment).expression, f, result); + result = reduceNode((node as SpreadAssignment).expression, cbNode, result); break; // Top-level nodes case SyntaxKind.SourceFile: - result = reduceLeft((node).statements, f, result); + result = reduceNodes((node).statements, cbNodes, result); break; case SyntaxKind.PartiallyEmittedExpression: - result = reduceNode((node).expression, f, result); + result = reduceNode((node).expression, cbNode, result); break; default: @@ -530,8 +536,8 @@ namespace ts { const value = (>node)[edge.name]; if (value !== undefined) { result = isArray(value) - ? reduceLeft(>value, f, result) - : f(result, value); + ? reduceNodes(>value, cbNodes, result) + : cbNode(result, value); } } } @@ -553,8 +559,8 @@ namespace ts { export function visitNode(node: T, visitor: (node: Node) => VisitResult, test: (node: Node) => boolean, optional?: boolean, lift?: (node: NodeArray) => T): T; export function visitNode(node: T, visitor: (node: Node) => VisitResult, test: (node: Node) => boolean, optional: boolean, lift: (node: NodeArray) => T, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node): T; export function visitNode(node: Node, visitor: (node: Node) => VisitResult, test: (node: Node) => boolean, optional?: boolean, lift?: (node: Node[]) => Node, parenthesize?: (node: Node, parentNode: Node) => Node, parentNode?: Node): Node { - if (node === undefined) { - return undefined; + if (node === undefined || visitor === undefined) { + return node; } aggregateTransformFlags(node); @@ -659,6 +665,30 @@ namespace ts { return updated || nodes; } + export function visitLexicalEnvironment(nodes: NodeArray, visitor: (node: Node) => VisitResult, context: LexicalEnvironment, start?: number) { + context.startLexicalEnvironment(); + const updated = visitNodes(nodes, visitor, isStatement, start); + const declarations = context.endLexicalEnvironment(); + return createNodeArray(concatenate(updated, declarations), updated); + } + + export function visitParameterList(nodes: NodeArray, visitor: (node: Node) => VisitResult, context: LexicalEnvironment) { + context.startLexicalEnvironment(); + return visitNodes(nodes, visitor, isParameter); + } + + export function visitFunctionBody(node: FunctionBody, visitor: (node: Node) => VisitResult, context: LexicalEnvironment): FunctionBody; + export function visitFunctionBody(node: ConciseBody, visitor: (node: Node) => VisitResult, context: LexicalEnvironment): ConciseBody; + export function visitFunctionBody(node: ConciseBody, visitor: (node: Node) => VisitResult, context: LexicalEnvironment) { + const visited = visitNode(node, visitor, isConciseBody); + const declarations = context.endLexicalEnvironment(); + if (some(declarations)) { + const block = convertToFunctionBody(visited); + return updateBlock(block, createNodeArray(concatenate(block.statements, declarations), block.statements)); + } + return visited; + } + /** * Visits each child of a Node using the supplied visitor, possibly returning a new Node of the same kind in its place. * @@ -721,41 +751,33 @@ namespace ts { visitNodes((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isPropertyName), visitNodes((node).typeParameters, visitor, isTypeParameter), - (context.startLexicalEnvironment(), visitNodes((node).parameters, visitor, isParameter)), + visitParameterList((node).parameters, visitor, context), visitNode((node).type, visitor, isTypeNode, /*optional*/ true), - mergeFunctionBodyLexicalEnvironment( - visitNode((node).body, visitor, isFunctionBody, /*optional*/ true), - context.endLexicalEnvironment())); + visitFunctionBody((node).body, visitor, context)); case SyntaxKind.Constructor: return updateConstructor(node, visitNodes((node).decorators, visitor, isDecorator), visitNodes((node).modifiers, visitor, isModifier), - (context.startLexicalEnvironment(), visitNodes((node).parameters, visitor, isParameter)), - mergeFunctionBodyLexicalEnvironment( - visitNode((node).body, visitor, isFunctionBody, /*optional*/ true), - context.endLexicalEnvironment())); + visitParameterList((node).parameters, visitor, context), + visitFunctionBody((node).body, visitor, context)); case SyntaxKind.GetAccessor: return updateGetAccessor(node, visitNodes((node).decorators, visitor, isDecorator), visitNodes((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isPropertyName), - (context.startLexicalEnvironment(), visitNodes((node).parameters, visitor, isParameter)), + visitParameterList((node).parameters, visitor, context), visitNode((node).type, visitor, isTypeNode, /*optional*/ true), - mergeFunctionBodyLexicalEnvironment( - visitNode((node).body, visitor, isFunctionBody, /*optional*/ true), - context.endLexicalEnvironment())); + visitFunctionBody((node).body, visitor, context)); case SyntaxKind.SetAccessor: return updateSetAccessor(node, visitNodes((node).decorators, visitor, isDecorator), visitNodes((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isPropertyName), - (context.startLexicalEnvironment(), visitNodes((node).parameters, visitor, isParameter)), - mergeFunctionBodyLexicalEnvironment( - visitNode((node).body, visitor, isFunctionBody, /*optional*/ true), - context.endLexicalEnvironment())); + visitParameterList((node).parameters, visitor, context), + visitFunctionBody((node).body, visitor, context)); // Binding patterns case SyntaxKind.ObjectBindingPattern: @@ -818,21 +840,17 @@ namespace ts { visitNodes((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isPropertyName), visitNodes((node).typeParameters, visitor, isTypeParameter), - (context.startLexicalEnvironment(), visitNodes((node).parameters, visitor, isParameter)), + visitParameterList((node).parameters, visitor, context), visitNode((node).type, visitor, isTypeNode, /*optional*/ true), - mergeFunctionBodyLexicalEnvironment( - visitNode((node).body, visitor, isFunctionBody, /*optional*/ true), - context.endLexicalEnvironment())); + visitFunctionBody((node).body, visitor, context)); case SyntaxKind.ArrowFunction: return updateArrowFunction(node, visitNodes((node).modifiers, visitor, isModifier), visitNodes((node).typeParameters, visitor, isTypeParameter), - (context.startLexicalEnvironment(), visitNodes((node).parameters, visitor, isParameter)), + visitParameterList((node).parameters, visitor, context), visitNode((node).type, visitor, isTypeNode, /*optional*/ true), - mergeFunctionBodyLexicalEnvironment( - visitNode((node).body, visitor, isConciseBody, /*optional*/ true), - context.endLexicalEnvironment())); + visitFunctionBody((node).body, visitor, context)); case SyntaxKind.DeleteExpression: return updateDelete(node, @@ -1003,11 +1021,9 @@ namespace ts { visitNodes((node).modifiers, visitor, isModifier), visitNode((node).name, visitor, isPropertyName), visitNodes((node).typeParameters, visitor, isTypeParameter), - (context.startLexicalEnvironment(), visitNodes((node).parameters, visitor, isParameter)), + visitParameterList((node).parameters, visitor, context), visitNode((node).type, visitor, isTypeNode, /*optional*/ true), - mergeFunctionBodyLexicalEnvironment( - visitNode((node).body, visitor, isFunctionBody, /*optional*/ true), - context.endLexicalEnvironment())); + visitFunctionBody((node).body, visitor, context)); case SyntaxKind.ClassDeclaration: return updateClassDeclaration(node, @@ -1139,13 +1155,8 @@ namespace ts { // Top-level nodes case SyntaxKind.SourceFile: - context.startLexicalEnvironment(); return updateSourceFileNode(node, - createNodeArray( - concatenate( - visitNodes((node).statements, visitor, isStatement), - context.endLexicalEnvironment()), - (node).statements)); + visitLexicalEnvironment((node).statements, visitor, context)); // Transformation nodes case SyntaxKind.PartiallyEmittedExpression: @@ -1249,13 +1260,25 @@ namespace ts { if (node === undefined) { return TransformFlags.None; } - else if (node.transformFlags & TransformFlags.HasComputedFlags) { + if (node.transformFlags & TransformFlags.HasComputedFlags) { return node.transformFlags & ~getTransformFlagsSubtreeExclusions(node.kind); } - else { - const subtreeFlags = aggregateTransformFlagsForSubtree(node); - return computeTransformFlagsForNode(node, subtreeFlags); + const subtreeFlags = aggregateTransformFlagsForSubtree(node); + return computeTransformFlagsForNode(node, subtreeFlags); + } + + function aggregateTransformFlagsForNodeArray(nodes: NodeArray): TransformFlags { + if (nodes === undefined) { + return TransformFlags.None; } + let subtreeFlags = TransformFlags.None; + let nodeArrayFlags = TransformFlags.None; + for (const node of nodes) { + subtreeFlags |= aggregateTransformFlagsForNode(node); + nodeArrayFlags |= node.transformFlags & ~TransformFlags.HasComputedFlags; + } + nodes.transformFlags = nodeArrayFlags | TransformFlags.HasComputedFlags; + return subtreeFlags; } /** @@ -1269,15 +1292,19 @@ namespace ts { } // Aggregate the transform flags of each child. - return reduceEachChild(node, aggregateTransformFlagsForChildNode, TransformFlags.None); + return reduceEachChild(node, TransformFlags.None, aggregateTransformFlagsForChildNode, aggregateTransformFlagsForChildNodes); } /** * Aggregates the TransformFlags of a child node with the TransformFlags of its * siblings. */ - function aggregateTransformFlagsForChildNode(transformFlags: TransformFlags, child: Node): TransformFlags { - return transformFlags | aggregateTransformFlagsForNode(child); + function aggregateTransformFlagsForChildNode(transformFlags: TransformFlags, node: Node): TransformFlags { + return transformFlags | aggregateTransformFlagsForNode(node); + } + + function aggregateTransformFlagsForChildNodes(transformFlags: TransformFlags, nodes: NodeArray): TransformFlags { + return transformFlags | aggregateTransformFlagsForNodeArray(nodes); } export namespace Debug { diff --git a/tests/baselines/reference/assignmentTypeNarrowing.js b/tests/baselines/reference/assignmentTypeNarrowing.js index 7c10dde65cc..92fd49d9941 100644 --- a/tests/baselines/reference/assignmentTypeNarrowing.js +++ b/tests/baselines/reference/assignmentTypeNarrowing.js @@ -37,17 +37,17 @@ x = [true][0]; x; // boolean _a = [1][0], x = _a === void 0 ? "" : _a; x; // string | number -(_b = { x: true }, x = _b.x, _b); +(x = { x: true }.x); x; // boolean -(_c = { y: 1 }, x = _c.y, _c); +(x = { y: 1 }.y); x; // number -(_d = { x: true }, _e = _d.x, x = _e === void 0 ? "" : _e, _d); +(_b = { x: true }.x, x = _b === void 0 ? "" : _b); x; // string | boolean -(_f = { y: 1 }, _g = _f.y, x = _g === void 0 ? /a/ : _g, _f); +(_c = { y: 1 }.y, x = _c === void 0 ? /a/ : _c); x; // number | RegExp var a; for (var _i = 0, a_1 = a; _i < a_1.length; _i++) { x = a_1[_i]; x; // string } -var _a, _b, _c, _d, _e, _f, _g; +var _a, _b, _c; diff --git a/tests/baselines/reference/asyncMethodWithSuper_es5.js b/tests/baselines/reference/asyncMethodWithSuper_es5.js index 9ceff6bab4e..235f2763f9f 100644 --- a/tests/baselines/reference/asyncMethodWithSuper_es5.js +++ b/tests/baselines/reference/asyncMethodWithSuper_es5.js @@ -81,8 +81,8 @@ var B = (function (_super) { // async method with assignment/destructuring on 'super' requires a binding B.prototype.advanced = function () { return __awaiter(this, void 0, void 0, function () { - var f, a, b, _a, _b; - return __generator(this, function (_c) { + var f, a, b; + return __generator(this, function (_a) { f = function () { }; // call with property access _super.prototype.x.call(this); @@ -95,9 +95,9 @@ var B = (function (_super) { // element access (assign) _super.prototype["x"] = f; // destructuring assign with property access - (_a = { f: f }, super.x = _a.f, _a); + (_super.prototype.x = { f: f }.f); // destructuring assign with element access - (_b = { f: f }, super["x"] = _b.f, _b); + (_super.prototype["x"] = { f: f }.f); return [2 /*return*/]; }); }); diff --git a/tests/baselines/reference/computedPropertiesInDestructuring1.js b/tests/baselines/reference/computedPropertiesInDestructuring1.js index 0bc4286ed7b..b0dc33a4b4e 100644 --- a/tests/baselines/reference/computedPropertiesInDestructuring1.js +++ b/tests/baselines/reference/computedPropertiesInDestructuring1.js @@ -65,11 +65,11 @@ function f5(_a) { var _f = foo(), bar6 = [{ bar: "bar" }][0][_f]; var _g = foo.toExponential(), bar7 = [{ bar: "bar" }][0][_g]; // destructuring assignment -(_h = { bar: "bar" }, _j = foo, bar = _h[_j], _h); -(_k = { bar: "bar" }, _l = "bar", bar2 = _k[_l], _k); -(_m = { bar: "bar" }, _o = foo2(), bar3 = _m[_o], _m); -_p = foo, bar4 = [{ bar: "bar" }][0][_p]; -_q = foo2(), bar5 = [{ bar: "bar" }][0][_q]; -_r = foo(), bar4 = [{ bar: "bar" }][0][_r]; -_s = (1 + {}), bar4 = [{ bar: "bar" }][0][_s]; -var _h, _j, _k, _l, _m, _o, _p, _q, _r, _s; +(_h = foo, bar = { bar: "bar" }[_h]); +(_j = "bar", bar2 = { bar: "bar" }[_j]); +(_k = foo2(), bar3 = { bar: "bar" }[_k]); +_l = foo, bar4 = [{ bar: "bar" }][0][_l]; +_m = foo2(), bar5 = [{ bar: "bar" }][0][_m]; +_o = foo(), bar4 = [{ bar: "bar" }][0][_o]; +_p = (1 + {}), bar4 = [{ bar: "bar" }][0][_p]; +var _h, _j, _k, _l, _m, _o, _p; diff --git a/tests/baselines/reference/declarationsAndAssignments.js b/tests/baselines/reference/declarationsAndAssignments.js index 018aa5522ca..3a2f9ef3b4e 100644 --- a/tests/baselines/reference/declarationsAndAssignments.js +++ b/tests/baselines/reference/declarationsAndAssignments.js @@ -300,8 +300,8 @@ function f18() { var a; var b; var aa; - (_a = { a: a, b: b }, a = _a.a, b = _a.b, _a); - (_b = { b: b, a: a }, a = _b.a, b = _b.b, _b); + (_a = { a: a, b: b }, a = _a.a, b = _a.b); + (_b = { b: b, a: a }, a = _b.a, b = _b.b); _c = [a, b], aa[0] = _c[0], b = _c[1]; _d = [b, a], a = _d[0], b = _d[1]; // Error _e = [2, "def"], _f = _e[0], a = _f === void 0 ? 1 : _f, _g = _e[1], b = _g === void 0 ? "abc" : _g; @@ -311,7 +311,7 @@ function f19() { var a, b; _a = [1, 2], a = _a[0], b = _a[1]; _b = [b, a], a = _b[0], b = _b[1]; - (_c = { b: b, a: a }, a = _c.a, b = _c.b, _c); + (_c = { b: b, a: a }, a = _c.a, b = _c.b); _d = [[2, 3]][0], _e = _d === void 0 ? [1, 2] : _d, a = _e[0], b = _e[1]; var x = (_f = [1, 2], a = _f[0], b = _f[1], _f); var _a, _b, _c, _d, _e, _f; diff --git a/tests/baselines/reference/destructuringAssignmentWithDefault.js b/tests/baselines/reference/destructuringAssignmentWithDefault.js index ce3837e1162..fe3ccdcee53 100644 --- a/tests/baselines/reference/destructuringAssignmentWithDefault.js +++ b/tests/baselines/reference/destructuringAssignmentWithDefault.js @@ -7,5 +7,5 @@ let x = 0; //// [destructuringAssignmentWithDefault.js] var a = {}; var x = 0; -(_a = a.x, x = _a === void 0 ? 1 : _a, a); +(_a = a.x, x = _a === void 0 ? 1 : _a); var _a; diff --git a/tests/baselines/reference/emptyAssignmentPatterns02_ES5.js b/tests/baselines/reference/emptyAssignmentPatterns02_ES5.js index 370e019104f..f5434d4a1c3 100644 --- a/tests/baselines/reference/emptyAssignmentPatterns02_ES5.js +++ b/tests/baselines/reference/emptyAssignmentPatterns02_ES5.js @@ -9,8 +9,8 @@ let x, y, z, a1, a2, a3; //// [emptyAssignmentPatterns02_ES5.js] var a; var x, y, z, a1, a2, a3; -(x = a.x, y = a.y, z = a.z, a); -(a1 = a[0], a2 = a[1], a3 = a[2], a); +(x = a.x, y = a.y, z = a.z); +(a1 = a[0], a2 = a[1], a3 = a[2]); //// [emptyAssignmentPatterns02_ES5.d.ts] diff --git a/tests/baselines/reference/emptyAssignmentPatterns04_ES5.js b/tests/baselines/reference/emptyAssignmentPatterns04_ES5.js index e6b3cc7e3f2..91559d18252 100644 --- a/tests/baselines/reference/emptyAssignmentPatterns04_ES5.js +++ b/tests/baselines/reference/emptyAssignmentPatterns04_ES5.js @@ -9,9 +9,8 @@ let x, y, z, a1, a2, a3; //// [emptyAssignmentPatterns04_ES5.js] var a; var x, y, z, a1, a2, a3; -(_a = a, x = _a.x, y = _a.y, z = _a.z, _a); -(_b = a, a1 = _b[0], a2 = _b[1], a3 = _b[2], _b); -var _a, _b; +(x = a.x, y = a.y, z = a.z); +(a1 = a[0], a2 = a[1], a3 = a[2]); //// [emptyAssignmentPatterns04_ES5.d.ts] diff --git a/tests/baselines/reference/initializePropertiesWithRenamedLet.js b/tests/baselines/reference/initializePropertiesWithRenamedLet.js index d53fed8c0f7..4abe488aa08 100644 --- a/tests/baselines/reference/initializePropertiesWithRenamedLet.js +++ b/tests/baselines/reference/initializePropertiesWithRenamedLet.js @@ -28,7 +28,6 @@ if (true) { var x_1 = { x: 0 }.x; var y_1 = { y: 0 }.y; var z_1; - (_a = { z: 0 }, z_1 = _a.z, _a); - (_b = { z: 0 }, z_1 = _b.z, _b); + (z_1 = { z: 0 }.z); + (z_1 = { z: 0 }.z); } -var _a, _b; diff --git a/tests/baselines/reference/missingAndExcessProperties.js b/tests/baselines/reference/missingAndExcessProperties.js index b9fcadd9519..daefe18eed7 100644 --- a/tests/baselines/reference/missingAndExcessProperties.js +++ b/tests/baselines/reference/missingAndExcessProperties.js @@ -45,10 +45,10 @@ function f1() { // Missing properties function f2() { var x, y; - (_a = {}, x = _a.x, y = _a.y, _a); - (_b = {}, _c = _b.x, x = _c === void 0 ? 1 : _c, y = _b.y, _b); - (_d = {}, x = _d.x, _e = _d.y, y = _e === void 0 ? 1 : _e, _d); - (_f = {}, _g = _f.x, x = _g === void 0 ? 1 : _g, _h = _f.y, y = _h === void 0 ? 1 : _h, _f); + (_a = {}, x = _a.x, y = _a.y); + (_b = {}, _c = _b.x, x = _c === void 0 ? 1 : _c, y = _b.y); + (_d = {}, x = _d.x, _e = _d.y, y = _e === void 0 ? 1 : _e); + (_f = {}, _g = _f.x, x = _g === void 0 ? 1 : _g, _h = _f.y, y = _h === void 0 ? 1 : _h); var _a, _b, _c, _d, _e, _f, _g, _h; } // Excess properties @@ -62,8 +62,8 @@ function f3() { function f4() { var x, y; ({ x: 0, y: 0 }); - (_a = { x: 0, y: 0 }, x = _a.x, _a); - (_b = { x: 0, y: 0 }, y = _b.y, _b); - (_c = { x: 0, y: 0 }, x = _c.x, y = _c.y, _c); - var _a, _b, _c; + (x = { x: 0, y: 0 }.x); + (y = { x: 0, y: 0 }.y); + (_a = { x: 0, y: 0 }, x = _a.x, y = _a.y); + var _a; } diff --git a/tests/baselines/reference/objectRest.js b/tests/baselines/reference/objectRest.js index a295ff7b9f1..519283b32e5 100644 --- a/tests/baselines/reference/objectRest.js +++ b/tests/baselines/reference/objectRest.js @@ -53,9 +53,9 @@ let nestedrest; var { x } = nestedrest, _a = nestedrest.n1, { y } = _a, _b = _a.n2, { z } = _b, nr = __rest(_b.n3, []), restrest = __rest(nestedrest, ["x", "n1"]); let complex; var _c = complex.x, { ka } = _c, nested = __rest(_c, ["ka"]), { y: other } = complex, rest = __rest(complex, ["x", "y"]); -(_d = complex.x, { ka } = _d, nested = __rest(_d, ["ka"]), { y: other } = complex, rest = __rest(complex, ["x", "y"]), complex); +(_d = complex.x, { ka } = _d, nested = __rest(_d, ["ka"]), { y: other } = complex, rest = __rest(complex, ["x", "y"])); var _e = { x: 1, y: 2 }, { x } = _e, fresh = __rest(_e, ["x"]); -(_f = { x: 1, y: 2 }, { x } = _f, fresh = __rest(_f, ["x"]), _f); +(_f = { x: 1, y: 2 }, { x } = _f, fresh = __rest(_f, ["x"])); class Removable { set z(value) { } get both() { return 12; } diff --git a/tests/baselines/reference/objectRestAssignment.js b/tests/baselines/reference/objectRestAssignment.js index 41620d59b58..d4d266d3fe5 100644 --- a/tests/baselines/reference/objectRestAssignment.js +++ b/tests/baselines/reference/objectRestAssignment.js @@ -26,10 +26,10 @@ let nested; let other; let rest; let complex; -(_a = complex.x, { ka } = _a, nested = __rest(_a, ["ka"]), { y: other } = complex, rest = __rest(complex, ["x", "y"]), complex); +(_a = complex.x, { ka } = _a, nested = __rest(_a, ["ka"]), { y: other } = complex, rest = __rest(complex, ["x", "y"])); // should be: let overEmit; // var _g = overEmit.a, [_h, ...y] = _g, nested2 = __rest(_h, []), _j = overEmit.b, { z } = _j, c = __rest(_j, ["z"]), rest2 = __rest(overEmit, ["a", "b"]); var _b = overEmit.a, [_c, ...y] = _b, nested2 = __rest(_c, []), _d = overEmit.b, { z } = _d, c = __rest(_d, ["z"]), rest2 = __rest(overEmit, ["a", "b"]); -(_e = overEmit.a, [_f, ...y] = _e, nested2 = __rest(_f, []), _g = overEmit.b, { z } = _g, c = __rest(_g, ["z"]), rest2 = __rest(overEmit, ["a", "b"]), overEmit); -var _a, _e, _f, _g; +(_e = overEmit.a, [_f, ...y] = _e, nested2 = __rest(_f, []), _g = overEmit.b, { z } = _g, c = __rest(_g, ["z"]), rest2 = __rest(overEmit, ["a", "b"])); +var _a, _e, _g; diff --git a/tests/baselines/reference/objectRestNegative.js b/tests/baselines/reference/objectRestNegative.js index b3b49740762..6a710a22870 100644 --- a/tests/baselines/reference/objectRestNegative.js +++ b/tests/baselines/reference/objectRestNegative.js @@ -17,9 +17,9 @@ var __rest = (this && this.__rest) || function (s, e) { return t; }; var o = { a: 1, b: 'no' }; -var mustBeLast = o.mustBeLast, a = o.a; +var a = o.a; function stillMustBeLast(_a) { - var mustBeLast = _a.mustBeLast, a = _a.a; + var a = _a.a; } function generic(t) { var x = t.x, rest = __rest(t, ["x"]); diff --git a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.js b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.js index 981ee08e20c..6be02246e39 100644 --- a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.js +++ b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.js @@ -176,63 +176,63 @@ function foo({a = 4, b = { x: 5 }}) { }); (function () { var y; - (_a = { y: 1 }, _b = _a.y, y = _b === void 0 ? 5 : _b, _a); - var _a, _b; + (_a = { y: 1 }.y, y = _a === void 0 ? 5 : _a); + var _a; }); (function () { var y; - (_a = { y: 1 }, _b = _a.y, y = _b === void 0 ? 5 : _b, _a); - var _a, _b; + (_a = { y: 1 }.y, y = _a === void 0 ? 5 : _a); + var _a; }); (function () { var y0; - (_a = { y0: 1 }, _b = _a.y0, y0 = _b === void 0 ? 5 : _b, _a); - var _a, _b; + (_a = { y0: 1 }.y0, y0 = _a === void 0 ? 5 : _a); + var _a; }); (function () { var y0; - (_a = { y0: 1 }, _b = _a.y0, y0 = _b === void 0 ? 5 : _b, _a); - var _a, _b; + (_a = { y0: 1 }.y0, y0 = _a === void 0 ? 5 : _a); + var _a; }); (function () { var y1; - (_a = {}, _b = _a.y1, y1 = _b === void 0 ? 5 : _b, _a); - var _a, _b; + (_a = {}.y1, y1 = _a === void 0 ? 5 : _a); + var _a; }); (function () { var y1; - (_a = {}, _b = _a.y1, y1 = _b === void 0 ? 5 : _b, _a); - var _a, _b; + (_a = {}.y1, y1 = _a === void 0 ? 5 : _a); + var _a; }); (function () { var y2, y3; - (_a = {}, _b = _a.y2, y2 = _b === void 0 ? 5 : _b, _c = _a.y3, y3 = _c === void 0 ? { x: 1 } : _c, _a); + (_a = {}, _b = _a.y2, y2 = _b === void 0 ? 5 : _b, _c = _a.y3, y3 = _c === void 0 ? { x: 1 } : _c); var _a, _b, _c; }); (function () { var y2, y3; - (_a = {}, _b = _a.y2, y2 = _b === void 0 ? 5 : _b, _c = _a.y3, y3 = _c === void 0 ? { x: 1 } : _c, _a); + (_a = {}, _b = _a.y2, y2 = _b === void 0 ? 5 : _b, _c = _a.y3, y3 = _c === void 0 ? { x: 1 } : _c); var _a, _b, _c; }); (function () { var y4, y5; - (_a = {}, _b = _a.y4, y4 = _b === void 0 ? 5 : _b, _c = _a.y5, y5 = _c === void 0 ? { x: 1 } : _c, _a); + (_a = {}, _b = _a.y4, y4 = _b === void 0 ? 5 : _b, _c = _a.y5, y5 = _c === void 0 ? { x: 1 } : _c); var _a, _b, _c; }); (function () { var y4, y5; - (_a = {}, _b = _a.y4, y4 = _b === void 0 ? 5 : _b, _c = _a.y5, y5 = _c === void 0 ? { x: 1 } : _c, _a); + (_a = {}, _b = _a.y4, y4 = _b === void 0 ? 5 : _b, _c = _a.y5, y5 = _c === void 0 ? { x: 1 } : _c); var _a, _b, _c; }); (function () { var z; - (_a = { z: { x: 1 } }, _b = _a.z, z = _b === void 0 ? { x: 5 } : _b, _a); - var _a, _b; + (_a = { z: { x: 1 } }.z, z = _a === void 0 ? { x: 5 } : _a); + var _a; }); (function () { var z; - (_a = { z: { x: 1 } }, _b = _a.z, z = _b === void 0 ? { x: 5 } : _b, _a); - var _a, _b; + (_a = { z: { x: 1 } }.z, z = _a === void 0 ? { x: 5 } : _a); + var _a; }); (function () { var a = { s: s }; From 08f467bd4cfd25393ee9993f536dc32a2ae0a6c6 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 14 Nov 2016 14:20:25 -0800 Subject: [PATCH 03/10] Clean up destructuring --- src/compiler/binder.ts | 39 +- src/compiler/factory.ts | 1094 ++++++++++++-------- src/compiler/transformers/destructuring.ts | 491 ++------- src/compiler/transformers/es2015.ts | 9 +- src/compiler/transformers/esnext.ts | 10 +- src/compiler/transformers/module/module.ts | 2 +- src/compiler/transformers/module/system.ts | 4 +- src/compiler/transformers/ts.ts | 2 +- src/compiler/types.ts | 64 +- src/compiler/utilities.ts | 72 ++ 10 files changed, 914 insertions(+), 873 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 9a477f05211..52131a90c3a 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1280,7 +1280,7 @@ namespace ts { function bindInitializedVariableFlow(node: VariableDeclaration | ArrayBindingElement) { const name = !isOmittedExpression(node) ? node.name : undefined; if (isBindingPattern(name)) { - for (const child of name.elements) { + for (const child of name.elements) { bindInitializedVariableFlow(child); } } @@ -2629,7 +2629,7 @@ namespace ts { } // parameters with object rest destructuring are ES Next syntax - if (subtreeFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)) { + if (subtreeFlags & TransformFlags.ContainsObjectRest) { transformFlags |= TransformFlags.AssertESNext; } @@ -2867,7 +2867,7 @@ namespace ts { } // function declarations with object rest destructuring are ES Next syntax - if (subtreeFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)) { + if (subtreeFlags & TransformFlags.ContainsObjectRest) { transformFlags |= TransformFlags.AssertESNext; } @@ -2909,7 +2909,7 @@ namespace ts { } // function expressions with object rest destructuring are ES Next syntax - if (subtreeFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)) { + if (subtreeFlags & TransformFlags.ContainsObjectRest) { transformFlags |= TransformFlags.AssertESNext; } @@ -2952,7 +2952,7 @@ namespace ts { } // arrow functions with object rest destructuring are ES Next syntax - if (subtreeFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)) { + if (subtreeFlags & TransformFlags.ContainsObjectRest) { transformFlags |= TransformFlags.AssertESNext; } @@ -2982,16 +2982,11 @@ namespace ts { function computeVariableDeclaration(node: VariableDeclaration, subtreeFlags: TransformFlags) { let transformFlags = subtreeFlags; - const nameKind = node.name.kind; + transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern; - // A VariableDeclaration with an object binding pattern is ES2015 syntax - // and possibly ESNext syntax if it contains an object binding pattern - if (nameKind === SyntaxKind.ObjectBindingPattern) { - transformFlags |= TransformFlags.AssertESNext | TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern; - } - // A VariableDeclaration with an object binding pattern is ES2015 syntax. - else if (nameKind === SyntaxKind.ArrayBindingPattern) { - transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern; + // A VariableDeclaration containing ObjectRest is ESNext syntax + if (subtreeFlags & TransformFlags.ContainsObjectRest) { + transformFlags |= TransformFlags.AssertESNext; } // Type annotations are TypeScript syntax. @@ -3213,13 +3208,6 @@ namespace ts { transformFlags |= TransformFlags.AssertESNext | TransformFlags.ContainsSpread | TransformFlags.ContainsObjectSpread; break; - case SyntaxKind.BindingElement: - transformFlags |= TransformFlags.AssertES2015; - if ((node).dotDotDotToken) { - transformFlags |= TransformFlags.ContainsRest; - } - break; - case SyntaxKind.SuperKeyword: // This node is ES6 syntax. transformFlags |= TransformFlags.AssertES2015; @@ -3232,7 +3220,7 @@ namespace ts { case SyntaxKind.ObjectBindingPattern: transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern; - if (subtreeFlags & TransformFlags.ContainsSpread) { + if (subtreeFlags & TransformFlags.ContainsRest) { transformFlags |= TransformFlags.AssertESNext | TransformFlags.ContainsObjectRest; } excludeFlags = TransformFlags.BindingPatternExcludes; @@ -3243,6 +3231,13 @@ namespace ts { excludeFlags = TransformFlags.BindingPatternExcludes; break; + case SyntaxKind.BindingElement: + transformFlags |= TransformFlags.AssertES2015; + if ((node).dotDotDotToken) { + transformFlags |= TransformFlags.ContainsRest; + } + break; + case SyntaxKind.Decorator: // This node is TypeScript syntax, and marks its container as also being TypeScript syntax. transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsDecorators; diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index ac3d5ed6e29..c107263b9d8 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -1405,7 +1405,7 @@ namespace ts { return node; } - export function updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression) { + export function updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression) { if (node.name !== name || node.objectAssignmentInitializer !== objectAssignmentInitializer) { return updateNode(createShorthandPropertyAssignment(name, objectAssignmentInitializer, node), node); } @@ -1419,7 +1419,7 @@ namespace ts { return node; } - // Top-level nodes + // Top-level nodes export function updateSourceFileNode(node: SourceFile, statements: Statement[]) { if (node.statements !== statements) { @@ -1994,6 +1994,8 @@ namespace ts { ); } + // Utilities + export interface CallBinding { target: LeftHandSideExpression; thisArg: Expression; @@ -2339,8 +2341,6 @@ namespace ts { return qualifiedName; } - // Utilities - export function convertToFunctionBody(node: ConciseBody) { if (isBlock(node)) { return node; @@ -2424,407 +2424,6 @@ namespace ts { return node; } - /** - * Wraps the operand to a BinaryExpression in parentheses if they are needed to preserve the intended - * order of operations. - * - * @param binaryOperator The operator for the BinaryExpression. - * @param operand The operand for the BinaryExpression. - * @param isLeftSideOfBinary A value indicating whether the operand is the left side of the - * BinaryExpression. - */ - export function parenthesizeBinaryOperand(binaryOperator: SyntaxKind, operand: Expression, isLeftSideOfBinary: boolean, leftOperand?: Expression) { - const skipped = skipPartiallyEmittedExpressions(operand); - - // If the resulting expression is already parenthesized, we do not need to do any further processing. - if (skipped.kind === SyntaxKind.ParenthesizedExpression) { - return operand; - } - - return binaryOperandNeedsParentheses(binaryOperator, operand, isLeftSideOfBinary, leftOperand) - ? createParen(operand) - : operand; - } - - /** - * Determines whether the operand to a BinaryExpression needs to be parenthesized. - * - * @param binaryOperator The operator for the BinaryExpression. - * @param operand The operand for the BinaryExpression. - * @param isLeftSideOfBinary A value indicating whether the operand is the left side of the - * BinaryExpression. - */ - function binaryOperandNeedsParentheses(binaryOperator: SyntaxKind, operand: Expression, isLeftSideOfBinary: boolean, leftOperand: Expression) { - // If the operand has lower precedence, then it needs to be parenthesized to preserve the - // intent of the expression. For example, if the operand is `a + b` and the operator is - // `*`, then we need to parenthesize the operand to preserve the intended order of - // operations: `(a + b) * x`. - // - // If the operand has higher precedence, then it does not need to be parenthesized. For - // example, if the operand is `a * b` and the operator is `+`, then we do not need to - // parenthesize to preserve the intended order of operations: `a * b + x`. - // - // If the operand has the same precedence, then we need to check the associativity of - // the operator based on whether this is the left or right operand of the expression. - // - // For example, if `a / d` is on the right of operator `*`, we need to parenthesize - // to preserve the intended order of operations: `x * (a / d)` - // - // If `a ** d` is on the left of operator `**`, we need to parenthesize to preserve - // the intended order of operations: `(a ** b) ** c` - const binaryOperatorPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, binaryOperator); - const binaryOperatorAssociativity = getOperatorAssociativity(SyntaxKind.BinaryExpression, binaryOperator); - const emittedOperand = skipPartiallyEmittedExpressions(operand); - const operandPrecedence = getExpressionPrecedence(emittedOperand); - switch (compareValues(operandPrecedence, binaryOperatorPrecedence)) { - case Comparison.LessThan: - // If the operand is the right side of a right-associative binary operation - // and is a yield expression, then we do not need parentheses. - if (!isLeftSideOfBinary - && binaryOperatorAssociativity === Associativity.Right - && operand.kind === SyntaxKind.YieldExpression) { - return false; - } - - return true; - - case Comparison.GreaterThan: - return false; - - case Comparison.EqualTo: - if (isLeftSideOfBinary) { - // No need to parenthesize the left operand when the binary operator is - // left associative: - // (a*b)/x -> a*b/x - // (a**b)/x -> a**b/x - // - // Parentheses are needed for the left operand when the binary operator is - // right associative: - // (a/b)**x -> (a/b)**x - // (a**b)**x -> (a**b)**x - return binaryOperatorAssociativity === Associativity.Right; - } - else { - if (isBinaryExpression(emittedOperand) - && emittedOperand.operatorToken.kind === binaryOperator) { - // No need to parenthesize the right operand when the binary operator and - // operand are the same and one of the following: - // x*(a*b) => x*a*b - // x|(a|b) => x|a|b - // x&(a&b) => x&a&b - // x^(a^b) => x^a^b - if (operatorHasAssociativeProperty(binaryOperator)) { - return false; - } - - // No need to parenthesize the right operand when the binary operator - // is plus (+) if both the left and right operands consist solely of either - // literals of the same kind or binary plus (+) expressions for literals of - // the same kind (recursively). - // "a"+(1+2) => "a"+(1+2) - // "a"+("b"+"c") => "a"+"b"+"c" - if (binaryOperator === SyntaxKind.PlusToken) { - const leftKind = leftOperand ? getLiteralKindOfBinaryPlusOperand(leftOperand) : SyntaxKind.Unknown; - if (isLiteralKind(leftKind) && leftKind === getLiteralKindOfBinaryPlusOperand(emittedOperand)) { - return false; - } - } - } - - // No need to parenthesize the right operand when the operand is right - // associative: - // x/(a**b) -> x/a**b - // x**(a**b) -> x**a**b - // - // Parentheses are needed for the right operand when the operand is left - // associative: - // x/(a*b) -> x/(a*b) - // x**(a/b) -> x**(a/b) - const operandAssociativity = getExpressionAssociativity(emittedOperand); - return operandAssociativity === Associativity.Left; - } - } - } - - /** - * Determines whether a binary operator is mathematically associative. - * - * @param binaryOperator The binary operator. - */ - function operatorHasAssociativeProperty(binaryOperator: SyntaxKind) { - // The following operators are associative in JavaScript: - // (a*b)*c -> a*(b*c) -> a*b*c - // (a|b)|c -> a|(b|c) -> a|b|c - // (a&b)&c -> a&(b&c) -> a&b&c - // (a^b)^c -> a^(b^c) -> a^b^c - // - // While addition is associative in mathematics, JavaScript's `+` is not - // guaranteed to be associative as it is overloaded with string concatenation. - return binaryOperator === SyntaxKind.AsteriskToken - || binaryOperator === SyntaxKind.BarToken - || binaryOperator === SyntaxKind.AmpersandToken - || binaryOperator === SyntaxKind.CaretToken; - } - - interface BinaryPlusExpression extends BinaryExpression { - cachedLiteralKind: SyntaxKind; - } - - /** - * This function determines whether an expression consists of a homogeneous set of - * literal expressions or binary plus expressions that all share the same literal kind. - * It is used to determine whether the right-hand operand of a binary plus expression can be - * emitted without parentheses. - */ - function getLiteralKindOfBinaryPlusOperand(node: Expression): SyntaxKind { - node = skipPartiallyEmittedExpressions(node); - - if (isLiteralKind(node.kind)) { - return node.kind; - } - - if (node.kind === SyntaxKind.BinaryExpression && (node).operatorToken.kind === SyntaxKind.PlusToken) { - if ((node).cachedLiteralKind !== undefined) { - return (node).cachedLiteralKind; - } - - const leftKind = getLiteralKindOfBinaryPlusOperand((node).left); - const literalKind = isLiteralKind(leftKind) - && leftKind === getLiteralKindOfBinaryPlusOperand((node).right) - ? leftKind - : SyntaxKind.Unknown; - - (node).cachedLiteralKind = literalKind; - return literalKind; - } - - return SyntaxKind.Unknown; - } - - /** - * Wraps an expression in parentheses if it is needed in order to use the expression - * as the expression of a NewExpression node. - * - * @param expression The Expression node. - */ - export function parenthesizeForNew(expression: Expression): LeftHandSideExpression { - const emittedExpression = skipPartiallyEmittedExpressions(expression); - switch (emittedExpression.kind) { - case SyntaxKind.CallExpression: - return createParen(expression); - - case SyntaxKind.NewExpression: - return (emittedExpression).arguments - ? expression - : createParen(expression); - } - - return parenthesizeForAccess(expression); - } - - /** - * Wraps an expression in parentheses if it is needed in order to use the expression for - * property or element access. - * - * @param expr The expression node. - */ - export function parenthesizeForAccess(expression: Expression): LeftHandSideExpression { - // isLeftHandSideExpression is almost the correct criterion for when it is not necessary - // to parenthesize the expression before a dot. The known exceptions are: - // - // NewExpression: - // new C.x -> not the same as (new C).x - // NumericLiteral - // 1.x -> not the same as (1).x - // - const emittedExpression = skipPartiallyEmittedExpressions(expression); - if (isLeftHandSideExpression(emittedExpression) - && (emittedExpression.kind !== SyntaxKind.NewExpression || (emittedExpression).arguments) - && emittedExpression.kind !== SyntaxKind.NumericLiteral) { - return expression; - } - - return createParen(expression, /*location*/ expression); - } - - export function parenthesizePostfixOperand(operand: Expression) { - return isLeftHandSideExpression(operand) - ? operand - : createParen(operand, /*location*/ operand); - } - - export function parenthesizePrefixOperand(operand: Expression) { - return isUnaryExpression(operand) - ? operand - : createParen(operand, /*location*/ operand); - } - - function parenthesizeListElements(elements: NodeArray) { - let result: Expression[]; - for (let i = 0; i < elements.length; i++) { - const element = parenthesizeExpressionForList(elements[i]); - if (result !== undefined || element !== elements[i]) { - if (result === undefined) { - result = elements.slice(0, i); - } - - result.push(element); - } - } - - if (result !== undefined) { - return createNodeArray(result, elements, elements.hasTrailingComma); - } - - return elements; - } - - export function parenthesizeExpressionForList(expression: Expression) { - const emittedExpression = skipPartiallyEmittedExpressions(expression); - const expressionPrecedence = getExpressionPrecedence(emittedExpression); - const commaPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, SyntaxKind.CommaToken); - return expressionPrecedence > commaPrecedence - ? expression - : createParen(expression, /*location*/ expression); - } - - export function parenthesizeExpressionForExpressionStatement(expression: Expression) { - const emittedExpression = skipPartiallyEmittedExpressions(expression); - if (isCallExpression(emittedExpression)) { - const callee = emittedExpression.expression; - const kind = skipPartiallyEmittedExpressions(callee).kind; - if (kind === SyntaxKind.FunctionExpression || kind === SyntaxKind.ArrowFunction) { - const mutableCall = getMutableClone(emittedExpression); - mutableCall.expression = createParen(callee, /*location*/ callee); - return recreatePartiallyEmittedExpressions(expression, mutableCall); - } - } - else { - const leftmostExpressionKind = getLeftmostExpression(emittedExpression).kind; - if (leftmostExpressionKind === SyntaxKind.ObjectLiteralExpression || leftmostExpressionKind === SyntaxKind.FunctionExpression) { - return createParen(expression, /*location*/ expression); - } - } - - return expression; - } - - /** - * Clones a series of not-emitted expressions with a new inner expression. - * - * @param originalOuterExpression The original outer expression. - * @param newInnerExpression The new inner expression. - */ - function recreatePartiallyEmittedExpressions(originalOuterExpression: Expression, newInnerExpression: Expression) { - if (isPartiallyEmittedExpression(originalOuterExpression)) { - const clone = getMutableClone(originalOuterExpression); - clone.expression = recreatePartiallyEmittedExpressions(clone.expression, newInnerExpression); - return clone; - } - - return newInnerExpression; - } - - function getLeftmostExpression(node: Expression): Expression { - while (true) { - switch (node.kind) { - case SyntaxKind.PostfixUnaryExpression: - node = (node).operand; - continue; - - case SyntaxKind.BinaryExpression: - node = (node).left; - continue; - - case SyntaxKind.ConditionalExpression: - node = (node).condition; - continue; - - case SyntaxKind.CallExpression: - case SyntaxKind.ElementAccessExpression: - case SyntaxKind.PropertyAccessExpression: - node = (node).expression; - continue; - - case SyntaxKind.PartiallyEmittedExpression: - node = (node).expression; - continue; - } - - return node; - } - } - - export function parenthesizeConciseBody(body: ConciseBody): ConciseBody { - const emittedBody = skipPartiallyEmittedExpressions(body); - if (emittedBody.kind === SyntaxKind.ObjectLiteralExpression) { - return createParen(body, /*location*/ body); - } - - return body; - } - - export const enum OuterExpressionKinds { - Parentheses = 1 << 0, - Assertions = 1 << 1, - PartiallyEmittedExpressions = 1 << 2, - - All = Parentheses | Assertions | PartiallyEmittedExpressions - } - - export function skipOuterExpressions(node: Expression, kinds?: OuterExpressionKinds): Expression; - export function skipOuterExpressions(node: Node, kinds?: OuterExpressionKinds): Node; - export function skipOuterExpressions(node: Node, kinds = OuterExpressionKinds.All) { - let previousNode: Node; - do { - previousNode = node; - if (kinds & OuterExpressionKinds.Parentheses) { - node = skipParentheses(node); - } - - if (kinds & OuterExpressionKinds.Assertions) { - node = skipAssertions(node); - } - - if (kinds & OuterExpressionKinds.PartiallyEmittedExpressions) { - node = skipPartiallyEmittedExpressions(node); - } - } - while (previousNode !== node); - - return node; - } - - export function skipParentheses(node: Expression): Expression; - export function skipParentheses(node: Node): Node; - export function skipParentheses(node: Node): Node { - while (node.kind === SyntaxKind.ParenthesizedExpression) { - node = (node).expression; - } - - return node; - } - - export function skipAssertions(node: Expression): Expression; - export function skipAssertions(node: Node): Node; - export function skipAssertions(node: Node): Node { - while (isAssertionExpression(node)) { - node = (node).expression; - } - - return node; - } - - export function skipPartiallyEmittedExpressions(node: Expression): Expression; - export function skipPartiallyEmittedExpressions(node: Node): Node; - export function skipPartiallyEmittedExpressions(node: Node) { - while (node.kind === SyntaxKind.PartiallyEmittedExpression) { - node = (node).expression; - } - - return node; - } - export function startOnNewLine(node: T): T { node.startsOnNewLine = true; return node; @@ -3295,7 +2894,7 @@ namespace ts { createVariableStatement( /*modifiers*/ undefined, createVariableDeclarationList( - flattenDestructuringToDeclarations( + flattenDestructuringBinding( context, parameter, temp, @@ -3454,9 +3053,6 @@ namespace ts { statements.push(forStatement); } - - - export function convertForOf(node: ForOfStatement, convertedLoopBodyStatements: Statement[], visitor: (node: Node) => VisitResult, enableSubstitutionsForBlockScopedBindings: () => void, @@ -3509,7 +3105,7 @@ namespace ts { if (firstOriginalDeclaration && isBindingPattern(firstOriginalDeclaration.name)) { // This works whether the declaration is a var, let, or const. // It will use rhsIterationValue _a[_i] as the initializer. - const declarations = flattenDestructuringToDeclarations( + const declarations = flattenDestructuringBinding( context, firstOriginalDeclaration, elementAccess, @@ -3566,7 +3162,7 @@ namespace ts { // This is a destructuring pattern, so we flatten the destructuring instead. statements.push( createStatement( - flattenDestructuringToExpression( + flattenDestructuringAssignment( context, assignment, /*needsValue*/ false, @@ -3651,4 +3247,680 @@ namespace ts { setEmitFlags(forStatement, EmitFlags.NoTokenTrailingSourceMaps); return forStatement; } + + /** + * Gets the initializer of an BindingOrAssignmentElement. + */ + export function getInitializerOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement): Expression | undefined { + if (isDeclarationBindingElement(bindingElement)) { + // `1` in `let { a = 1 } = ...` + // `1` in `let { a: b = 1 } = ...` + // `1` in `let { a: {b} = 1 } = ...` + // `1` in `let { a: [b] = 1 } = ...` + // `1` in `let [a = 1] = ...` + // `1` in `let [{a} = 1] = ...` + // `1` in `let [[a] = 1] = ...` + return bindingElement.initializer; + } + + if (isPropertyAssignment(bindingElement)) { + // `1` in `({ a: b = 1 } = ...)` + // `1` in `({ a: {b} = 1 } = ...)` + // `1` in `({ a: [b] = 1 } = ...)` + return isAssignmentExpression(bindingElement.initializer, /*excludeCompoundAssignment*/ true) + ? bindingElement.initializer.right + : undefined; + } + + if (isShorthandPropertyAssignment(bindingElement)) { + // `1` in `({ a = 1 } = ...)` + return bindingElement.objectAssignmentInitializer; + } + + if (isAssignmentExpression(bindingElement, /*excludeCompoundAssignment*/ true)) { + // `1` in `[a = 1] = ...` + // `1` in `[{a} = 1] = ...` + // `1` in `[[a] = 1] = ...` + return bindingElement.right; + } + + if (isSpreadExpression(bindingElement) && isBindingOrAssignmentElement(bindingElement.expression)) { + // Recovery consistent with existing emit. + return getInitializerOfBindingOrAssignmentElement(bindingElement.expression); + } + } + + /** + * Gets the name of an BindingOrAssignmentElement. + */ + export function getTargetOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement): BindingOrAssignmentElementTarget { + if (isDeclarationBindingElement(bindingElement)) { + // `a` in `let { a } = ...` + // `a` in `let { a = 1 } = ...` + // `b` in `let { a: b } = ...` + // `b` in `let { a: b = 1 } = ...` + // `a` in `let { ...a } = ...` + // `{b}` in `let { a: {b} } = ...` + // `{b}` in `let { a: {b} = 1 } = ...` + // `[b]` in `let { a: [b] } = ...` + // `[b]` in `let { a: [b] = 1 } = ...` + // `a` in `let [a] = ...` + // `a` in `let [a = 1] = ...` + // `a` in `let [...a] = ...` + // `{a}` in `let [{a}] = ...` + // `{a}` in `let [{a} = 1] = ...` + // `[a]` in `let [[a]] = ...` + // `[a]` in `let [[a] = 1] = ...` + return bindingElement.name; + } + + if (isObjectLiteralElementLike(bindingElement)) { + switch (bindingElement.kind) { + case SyntaxKind.PropertyAssignment: + // `b` in `({ a: b } = ...)` + // `b` in `({ a: b = 1 } = ...)` + // `{b}` in `({ a: {b} } = ...)` + // `{b}` in `({ a: {b} = 1 } = ...)` + // `[b]` in `({ a: [b] } = ...)` + // `[b]` in `({ a: [b] = 1 } = ...)` + // `b.c` in `({ a: b.c } = ...)` + // `b.c` in `({ a: b.c = 1 } = ...)` + // `b[0]` in `({ a: b[0] } = ...)` + // `b[0]` in `({ a: b[0] = 1 } = ...)` + return isBindingOrAssignmentElement(bindingElement.initializer) + ? getTargetOfBindingOrAssignmentElement(bindingElement.initializer) + : undefined; + + case SyntaxKind.ShorthandPropertyAssignment: + // `a` in `({ a } = ...)` + // `a` in `({ a = 1 } = ...)` + return bindingElement.name; + + case SyntaxKind.SpreadAssignment: + // `a` in `({ ...a } = ...)` + return isBindingOrAssignmentElement(bindingElement.expression) + ? getTargetOfBindingOrAssignmentElement(bindingElement.expression) + : undefined; + } + + // no target + return undefined; + } + + if (isAssignmentExpression(bindingElement, /*excludeCompoundAssignment*/ true)) { + // `a` in `[a = 1] = ...` + // `{a}` in `[{a} = 1] = ...` + // `[a]` in `[[a] = 1] = ...` + // `a.b` in `[a.b = 1] = ...` + // `a[0]` in `[a[0] = 1] = ...` + return isBindingOrAssignmentElement(bindingElement.left) + ? getTargetOfBindingOrAssignmentElement(bindingElement.left) + : undefined; + } + + if (isSpreadExpression(bindingElement)) { + // `a` in `[...a] = ...` + return isBindingOrAssignmentElement(bindingElement.expression) + ? getTargetOfBindingOrAssignmentElement(bindingElement.expression) + : undefined; + } + + // `a` in `[a] = ...` + // `{a}` in `[{a}] = ...` + // `[a]` in `[[a]] = ...` + // `a.b` in `[a.b] = ...` + // `a[0]` in `[a[0]] = ...` + return bindingElement; + } + + /** + * Determines whether an BindingOrAssignmentElement is a rest element. + */ + export function getRestIndicatorOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement): BindingOrAssignmentElementRestIndicator { + switch (bindingElement.kind) { + case SyntaxKind.Parameter: + case SyntaxKind.BindingElement: + // `...` in `let [...a] = ...` + return (bindingElement).dotDotDotToken; + + case SyntaxKind.SpreadElement: + case SyntaxKind.SpreadAssignment: + // `...` in `[...a] = ...` + return bindingElement; + } + + return undefined; + } + + /** + * Gets the property name of a BindingOrAssignmentElement + */ + export function getPropertyNameOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement) { + switch (bindingElement.kind) { + case SyntaxKind.BindingElement: + // `a` in `let { a: b } = ...` + // `[a]` in `let { [a]: b } = ...` + // `"a"` in `let { "a": b } = ...` + // `1` in `let { 1: b } = ...` + if ((bindingElement).propertyName) { + return (bindingElement).propertyName; + } + + break; + + case SyntaxKind.PropertyAssignment: + // `a` in `({ a: b } = ...)` + // `[a]` in `({ [a]: b } = ...)` + // `"a"` in `({ "a": b } = ...)` + // `1` in `({ 1: b } = ...)` + if ((bindingElement).name) { + return (bindingElement).name; + } + + break; + + case SyntaxKind.SpreadAssignment: + // `a` in `({ ...a } = ...)` + return (bindingElement).name; + } + + const target = getTargetOfBindingOrAssignmentElement(bindingElement); + if (target && isPropertyName(target)) { + return target; + } + + Debug.fail("Invalid property name for binding element."); + } + + /** + * Gets the elements of a BindingOrAssignmentPattern + */ + export function getElementsOfBindingOrAssignmentPattern(name: BindingOrAssignmentPattern): BindingOrAssignmentElement[] { + switch (name.kind) { + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: + case SyntaxKind.ArrayLiteralExpression: + // `a` in `{a}` + // `a` in `[a]` + return map(name.elements, convertToBindingOrAssignmentElement); + + case SyntaxKind.ObjectLiteralExpression: + // `a` in `{a}` + return filter(name.properties, isBindingOrAssignmentElement); + } + } + + function convertToBindingOrAssignmentElement(node: Node) { + return isBindingOrAssignmentElement(node) ? node : createOmittedExpression(node); + } + + export function convertToArrayAssignmentElement(element: BindingOrAssignmentElement) { + if (isBindingElement(element)) { + if (element.dotDotDotToken) { + Debug.assertNode(element.name, isIdentifier); + return setOriginalNode(createSpread(element.name, element), element); + } + const expression = convertToAssignmentElementTarget(element.name); + return element.initializer ? setOriginalNode(createAssignment(expression, element.initializer, element), element) : expression; + } + Debug.assertNode(element, isExpression); + return element; + } + + export function convertToObjectAssignmentElement(element: BindingOrAssignmentElement) { + if (isBindingElement(element)) { + if (element.dotDotDotToken) { + Debug.assertNode(element.name, isIdentifier); + return setOriginalNode(createSpreadAssignment(element.name, element), element); + } + if (element.propertyName) { + const expression = convertToAssignmentElementTarget(element.name); + return setOriginalNode(createPropertyAssignment(element.propertyName, element.initializer ? createAssignment(expression, element.initializer) : expression, element), element); + } + Debug.assertNode(element.name, isIdentifier); + return setOriginalNode(createShorthandPropertyAssignment(element.name, element.initializer, element), element); + } + Debug.assertNode(element, isObjectLiteralElementLike); + return element; + } + + export function convertToAssignmentPattern(node: BindingOrAssignmentPattern): AssignmentPattern { + switch (node.kind) { + case SyntaxKind.ArrayBindingPattern: + case SyntaxKind.ArrayLiteralExpression: + return convertToArrayAssignmentPattern(node); + + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ObjectLiteralExpression: + return convertToObjectAssignmentPattern(node); + } + } + + export function convertToObjectAssignmentPattern(node: ObjectBindingOrAssignmentPattern) { + if (isObjectBindingPattern(node)) { + return setOriginalNode(createObjectLiteral(map(node.elements, convertToObjectAssignmentElement), node), node); + } + Debug.assertNode(node, isObjectLiteralExpression); + return node; + } + + export function convertToArrayAssignmentPattern(node: ArrayBindingOrAssignmentPattern) { + if (isArrayBindingPattern(node)) { + return setOriginalNode(createArrayLiteral(map(node.elements, convertToArrayAssignmentElement), node), node); + } + Debug.assertNode(node, isArrayLiteralExpression); + return node; + } + + export function convertToAssignmentElementTarget(node: BindingOrAssignmentElementTarget): Expression { + if (isBindingPattern(node)) { + return convertToAssignmentPattern(node); + } + + Debug.assertNode(node, isExpression); + return node; + } + + // Parenthesizing + + /** + * Wraps the operand to a BinaryExpression in parentheses if they are needed to preserve the intended + * order of operations. + * + * @param binaryOperator The operator for the BinaryExpression. + * @param operand The operand for the BinaryExpression. + * @param isLeftSideOfBinary A value indicating whether the operand is the left side of the + * BinaryExpression. + */ + export function parenthesizeBinaryOperand(binaryOperator: SyntaxKind, operand: Expression, isLeftSideOfBinary: boolean, leftOperand?: Expression) { + const skipped = skipPartiallyEmittedExpressions(operand); + + // If the resulting expression is already parenthesized, we do not need to do any further processing. + if (skipped.kind === SyntaxKind.ParenthesizedExpression) { + return operand; + } + + return binaryOperandNeedsParentheses(binaryOperator, operand, isLeftSideOfBinary, leftOperand) + ? createParen(operand) + : operand; + } + + /** + * Determines whether the operand to a BinaryExpression needs to be parenthesized. + * + * @param binaryOperator The operator for the BinaryExpression. + * @param operand The operand for the BinaryExpression. + * @param isLeftSideOfBinary A value indicating whether the operand is the left side of the + * BinaryExpression. + */ + function binaryOperandNeedsParentheses(binaryOperator: SyntaxKind, operand: Expression, isLeftSideOfBinary: boolean, leftOperand: Expression) { + // If the operand has lower precedence, then it needs to be parenthesized to preserve the + // intent of the expression. For example, if the operand is `a + b` and the operator is + // `*`, then we need to parenthesize the operand to preserve the intended order of + // operations: `(a + b) * x`. + // + // If the operand has higher precedence, then it does not need to be parenthesized. For + // example, if the operand is `a * b` and the operator is `+`, then we do not need to + // parenthesize to preserve the intended order of operations: `a * b + x`. + // + // If the operand has the same precedence, then we need to check the associativity of + // the operator based on whether this is the left or right operand of the expression. + // + // For example, if `a / d` is on the right of operator `*`, we need to parenthesize + // to preserve the intended order of operations: `x * (a / d)` + // + // If `a ** d` is on the left of operator `**`, we need to parenthesize to preserve + // the intended order of operations: `(a ** b) ** c` + const binaryOperatorPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, binaryOperator); + const binaryOperatorAssociativity = getOperatorAssociativity(SyntaxKind.BinaryExpression, binaryOperator); + const emittedOperand = skipPartiallyEmittedExpressions(operand); + const operandPrecedence = getExpressionPrecedence(emittedOperand); + switch (compareValues(operandPrecedence, binaryOperatorPrecedence)) { + case Comparison.LessThan: + // If the operand is the right side of a right-associative binary operation + // and is a yield expression, then we do not need parentheses. + if (!isLeftSideOfBinary + && binaryOperatorAssociativity === Associativity.Right + && operand.kind === SyntaxKind.YieldExpression) { + return false; + } + + return true; + + case Comparison.GreaterThan: + return false; + + case Comparison.EqualTo: + if (isLeftSideOfBinary) { + // No need to parenthesize the left operand when the binary operator is + // left associative: + // (a*b)/x -> a*b/x + // (a**b)/x -> a**b/x + // + // Parentheses are needed for the left operand when the binary operator is + // right associative: + // (a/b)**x -> (a/b)**x + // (a**b)**x -> (a**b)**x + return binaryOperatorAssociativity === Associativity.Right; + } + else { + if (isBinaryExpression(emittedOperand) + && emittedOperand.operatorToken.kind === binaryOperator) { + // No need to parenthesize the right operand when the binary operator and + // operand are the same and one of the following: + // x*(a*b) => x*a*b + // x|(a|b) => x|a|b + // x&(a&b) => x&a&b + // x^(a^b) => x^a^b + if (operatorHasAssociativeProperty(binaryOperator)) { + return false; + } + + // No need to parenthesize the right operand when the binary operator + // is plus (+) if both the left and right operands consist solely of either + // literals of the same kind or binary plus (+) expressions for literals of + // the same kind (recursively). + // "a"+(1+2) => "a"+(1+2) + // "a"+("b"+"c") => "a"+"b"+"c" + if (binaryOperator === SyntaxKind.PlusToken) { + const leftKind = leftOperand ? getLiteralKindOfBinaryPlusOperand(leftOperand) : SyntaxKind.Unknown; + if (isLiteralKind(leftKind) && leftKind === getLiteralKindOfBinaryPlusOperand(emittedOperand)) { + return false; + } + } + } + + // No need to parenthesize the right operand when the operand is right + // associative: + // x/(a**b) -> x/a**b + // x**(a**b) -> x**a**b + // + // Parentheses are needed for the right operand when the operand is left + // associative: + // x/(a*b) -> x/(a*b) + // x**(a/b) -> x**(a/b) + const operandAssociativity = getExpressionAssociativity(emittedOperand); + return operandAssociativity === Associativity.Left; + } + } + } + + /** + * Determines whether a binary operator is mathematically associative. + * + * @param binaryOperator The binary operator. + */ + function operatorHasAssociativeProperty(binaryOperator: SyntaxKind) { + // The following operators are associative in JavaScript: + // (a*b)*c -> a*(b*c) -> a*b*c + // (a|b)|c -> a|(b|c) -> a|b|c + // (a&b)&c -> a&(b&c) -> a&b&c + // (a^b)^c -> a^(b^c) -> a^b^c + // + // While addition is associative in mathematics, JavaScript's `+` is not + // guaranteed to be associative as it is overloaded with string concatenation. + return binaryOperator === SyntaxKind.AsteriskToken + || binaryOperator === SyntaxKind.BarToken + || binaryOperator === SyntaxKind.AmpersandToken + || binaryOperator === SyntaxKind.CaretToken; + } + + interface BinaryPlusExpression extends BinaryExpression { + cachedLiteralKind: SyntaxKind; + } + + /** + * This function determines whether an expression consists of a homogeneous set of + * literal expressions or binary plus expressions that all share the same literal kind. + * It is used to determine whether the right-hand operand of a binary plus expression can be + * emitted without parentheses. + */ + function getLiteralKindOfBinaryPlusOperand(node: Expression): SyntaxKind { + node = skipPartiallyEmittedExpressions(node); + + if (isLiteralKind(node.kind)) { + return node.kind; + } + + if (node.kind === SyntaxKind.BinaryExpression && (node).operatorToken.kind === SyntaxKind.PlusToken) { + if ((node).cachedLiteralKind !== undefined) { + return (node).cachedLiteralKind; + } + + const leftKind = getLiteralKindOfBinaryPlusOperand((node).left); + const literalKind = isLiteralKind(leftKind) + && leftKind === getLiteralKindOfBinaryPlusOperand((node).right) + ? leftKind + : SyntaxKind.Unknown; + + (node).cachedLiteralKind = literalKind; + return literalKind; + } + + return SyntaxKind.Unknown; + } + + /** + * Wraps an expression in parentheses if it is needed in order to use the expression + * as the expression of a NewExpression node. + * + * @param expression The Expression node. + */ + export function parenthesizeForNew(expression: Expression): LeftHandSideExpression { + const emittedExpression = skipPartiallyEmittedExpressions(expression); + switch (emittedExpression.kind) { + case SyntaxKind.CallExpression: + return createParen(expression); + + case SyntaxKind.NewExpression: + return (emittedExpression).arguments + ? expression + : createParen(expression); + } + + return parenthesizeForAccess(expression); + } + + /** + * Wraps an expression in parentheses if it is needed in order to use the expression for + * property or element access. + * + * @param expr The expression node. + */ + export function parenthesizeForAccess(expression: Expression): LeftHandSideExpression { + // isLeftHandSideExpression is almost the correct criterion for when it is not necessary + // to parenthesize the expression before a dot. The known exceptions are: + // + // NewExpression: + // new C.x -> not the same as (new C).x + // NumericLiteral + // 1.x -> not the same as (1).x + // + const emittedExpression = skipPartiallyEmittedExpressions(expression); + if (isLeftHandSideExpression(emittedExpression) + && (emittedExpression.kind !== SyntaxKind.NewExpression || (emittedExpression).arguments) + && emittedExpression.kind !== SyntaxKind.NumericLiteral) { + return expression; + } + + return createParen(expression, /*location*/ expression); + } + + export function parenthesizePostfixOperand(operand: Expression) { + return isLeftHandSideExpression(operand) + ? operand + : createParen(operand, /*location*/ operand); + } + + export function parenthesizePrefixOperand(operand: Expression) { + return isUnaryExpression(operand) + ? operand + : createParen(operand, /*location*/ operand); + } + + function parenthesizeListElements(elements: NodeArray) { + let result: Expression[]; + for (let i = 0; i < elements.length; i++) { + const element = parenthesizeExpressionForList(elements[i]); + if (result !== undefined || element !== elements[i]) { + if (result === undefined) { + result = elements.slice(0, i); + } + + result.push(element); + } + } + + if (result !== undefined) { + return createNodeArray(result, elements, elements.hasTrailingComma); + } + + return elements; + } + + export function parenthesizeExpressionForList(expression: Expression) { + const emittedExpression = skipPartiallyEmittedExpressions(expression); + const expressionPrecedence = getExpressionPrecedence(emittedExpression); + const commaPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, SyntaxKind.CommaToken); + return expressionPrecedence > commaPrecedence + ? expression + : createParen(expression, /*location*/ expression); + } + + export function parenthesizeExpressionForExpressionStatement(expression: Expression) { + const emittedExpression = skipPartiallyEmittedExpressions(expression); + if (isCallExpression(emittedExpression)) { + const callee = emittedExpression.expression; + const kind = skipPartiallyEmittedExpressions(callee).kind; + if (kind === SyntaxKind.FunctionExpression || kind === SyntaxKind.ArrowFunction) { + const mutableCall = getMutableClone(emittedExpression); + mutableCall.expression = createParen(callee, /*location*/ callee); + return recreatePartiallyEmittedExpressions(expression, mutableCall); + } + } + else { + const leftmostExpressionKind = getLeftmostExpression(emittedExpression).kind; + if (leftmostExpressionKind === SyntaxKind.ObjectLiteralExpression || leftmostExpressionKind === SyntaxKind.FunctionExpression) { + return createParen(expression, /*location*/ expression); + } + } + + return expression; + } + + /** + * Clones a series of not-emitted expressions with a new inner expression. + * + * @param originalOuterExpression The original outer expression. + * @param newInnerExpression The new inner expression. + */ + function recreatePartiallyEmittedExpressions(originalOuterExpression: Expression, newInnerExpression: Expression) { + if (isPartiallyEmittedExpression(originalOuterExpression)) { + const clone = getMutableClone(originalOuterExpression); + clone.expression = recreatePartiallyEmittedExpressions(clone.expression, newInnerExpression); + return clone; + } + + return newInnerExpression; + } + + function getLeftmostExpression(node: Expression): Expression { + while (true) { + switch (node.kind) { + case SyntaxKind.PostfixUnaryExpression: + node = (node).operand; + continue; + + case SyntaxKind.BinaryExpression: + node = (node).left; + continue; + + case SyntaxKind.ConditionalExpression: + node = (node).condition; + continue; + + case SyntaxKind.CallExpression: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.PropertyAccessExpression: + node = (node).expression; + continue; + + case SyntaxKind.PartiallyEmittedExpression: + node = (node).expression; + continue; + } + + return node; + } + } + + export function parenthesizeConciseBody(body: ConciseBody): ConciseBody { + const emittedBody = skipPartiallyEmittedExpressions(body); + if (emittedBody.kind === SyntaxKind.ObjectLiteralExpression) { + return createParen(body, /*location*/ body); + } + + return body; + } + + export const enum OuterExpressionKinds { + Parentheses = 1 << 0, + Assertions = 1 << 1, + PartiallyEmittedExpressions = 1 << 2, + + All = Parentheses | Assertions | PartiallyEmittedExpressions + } + + export function skipOuterExpressions(node: Expression, kinds?: OuterExpressionKinds): Expression; + export function skipOuterExpressions(node: Node, kinds?: OuterExpressionKinds): Node; + export function skipOuterExpressions(node: Node, kinds = OuterExpressionKinds.All) { + let previousNode: Node; + do { + previousNode = node; + if (kinds & OuterExpressionKinds.Parentheses) { + node = skipParentheses(node); + } + + if (kinds & OuterExpressionKinds.Assertions) { + node = skipAssertions(node); + } + + if (kinds & OuterExpressionKinds.PartiallyEmittedExpressions) { + node = skipPartiallyEmittedExpressions(node); + } + } + while (previousNode !== node); + + return node; + } + + export function skipParentheses(node: Expression): Expression; + export function skipParentheses(node: Node): Node; + export function skipParentheses(node: Node): Node { + while (node.kind === SyntaxKind.ParenthesizedExpression) { + node = (node).expression; + } + + return node; + } + + export function skipAssertions(node: Expression): Expression; + export function skipAssertions(node: Node): Node; + export function skipAssertions(node: Node): Node { + while (isAssertionExpression(node)) { + node = (node).expression; + } + + return node; + } + + export function skipPartiallyEmittedExpressions(node: Expression): Expression; + export function skipPartiallyEmittedExpressions(node: Node): Node; + export function skipPartiallyEmittedExpressions(node: Node) { + while (node.kind === SyntaxKind.PartiallyEmittedExpression) { + node = (node).expression; + } + + return node; + } } diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index d4886457062..b8da29ae291 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -3,80 +3,21 @@ /*@internal*/ namespace ts { - type EffectiveBindingOrAssignmentElement = VariableDeclaration | ParameterDeclaration | BindingElement | ObjectLiteralElementLike | Expression; - type EffectiveObjectBindingOrAssignmentPattern = ObjectBindingPattern | ObjectLiteralExpression; - type EffectiveArrayBindingOrAssignmentPattern = ArrayBindingPattern | ArrayLiteralExpression; - type EffectiveBindingOrAssignmentPattern = EffectiveObjectBindingOrAssignmentPattern | EffectiveArrayBindingOrAssignmentPattern; - type EffectiveBindingOrAssignmentTarget = EffectiveBindingOrAssignmentPattern | Expression; - type EffectiveBindingOrAssignmentRestIndicator = DotDotDotToken | SpreadElement | SpreadAssignment; - interface FlattenHost { context: TransformationContext; level: FlattenLevel; recordTempVariablesInLine: boolean; emitExpression: (value: Expression) => void; - emitBindingOrAssignment: (target: EffectiveBindingOrAssignmentTarget, value: Expression, location: TextRange, original: Node) => void; - createArrayBindingOrAssignmentPattern: (elements: EffectiveBindingOrAssignmentElement[]) => EffectiveArrayBindingOrAssignmentPattern; - createObjectBindingOrAssignmentPattern: (elements: EffectiveBindingOrAssignmentElement[]) => EffectiveObjectBindingOrAssignmentPattern; - createArrayBindingOrAssignmentElement: (node: Identifier) => EffectiveBindingOrAssignmentElement; + emitBindingOrAssignment: (target: BindingOrAssignmentElementTarget, value: Expression, location: TextRange, original: Node) => void; + createArrayBindingOrAssignmentPattern: (elements: BindingOrAssignmentElement[]) => ArrayBindingOrAssignmentPattern; + createObjectBindingOrAssignmentPattern: (elements: BindingOrAssignmentElement[]) => ObjectBindingOrAssignmentPattern; + createArrayBindingOrAssignmentElement: (node: Identifier) => BindingOrAssignmentElement; visitor?: (node: Node) => VisitResult; } export const enum FlattenLevel { - ObjectRest, All, - } - - export const enum FlattenOutput { - Expression, - Declarations - } - - export const enum FlattenOptions { - NeedsValue = 1 << 0, - SkipInitializer = 1 << 1, - RecordTempVariablesInLine = 1 << 2, - } - - export function flattenDestructuring( - output: FlattenOutput.Expression, - level: FlattenLevel, - node: VariableDeclaration | DestructuringAssignment, - visitor: (node: Node) => VisitResult, - context: TransformationContext, - options: FlattenOptions, - createAssignment?: (name: Identifier, value: Expression, location?: TextRange) => Expression): Expression; - export function flattenDestructuring( - output: FlattenOutput.Declarations, - level: FlattenLevel, - node: VariableDeclaration | ParameterDeclaration, - visitor: (node: Node) => VisitResult, - context: TransformationContext, - options: FlattenOptions, - boundValue?: Expression): VariableDeclaration[]; - export function flattenDestructuring( - _output: FlattenOutput, - _level: FlattenLevel, - _node: VariableDeclaration | ParameterDeclaration | DestructuringAssignment, - _visitor: (node: Node) => VisitResult, - _context: TransformationContext, - _options: FlattenOptions, - _valueOrCallback?: Expression | ((name: Identifier, value: Expression, location?: TextRange) => Expression)): Expression | VariableDeclaration[] { - // const flattenMode = flags & FlattenFlags.FlattenMask; - // const outputMode = flags & FlattenFlags.OutputMask; - // const options = flags & FlattenFlags.OptionsMask; - - - // if (outputMode === FlattenFlags.OutputExpressions) { - // return flattenDestructuringToExpression(context, node, !(options & FlattenFlags.NeedsValue), flattenMode, createAssignmentCallback, visitor); - // } - // else { - // return flattenDestructuringToDeclarations( - // context, - // node, - // boundValue) - // } - return; + ObjectRest, } /** @@ -90,7 +31,7 @@ namespace ts { * @param createAssignmentCallback A callback used to create the assignment expression. * @param visitor A visitor used to visit initializers. */ - export function flattenDestructuringToExpression( + export function flattenDestructuringAssignment( context: TransformationContext, node: VariableDeclaration | DestructuringAssignment, needsValue: boolean, @@ -120,9 +61,9 @@ namespace ts { recordTempVariablesInLine: false, emitExpression, emitBindingOrAssignment, - createArrayBindingOrAssignmentPattern: createEffectiveArrayAssignmentPattern, - createObjectBindingOrAssignmentPattern: createEffectiveObjectAssignmentPattern, - createArrayBindingOrAssignmentElement: createEffectiveAssignmentElement, + createArrayBindingOrAssignmentPattern: makeArrayAssignmentPattern, + createObjectBindingOrAssignmentPattern: makeObjectAssignmentPattern, + createArrayBindingOrAssignmentElement: makeAssignmentElement, visitor }; @@ -148,7 +89,7 @@ namespace ts { } } - flattenEffectiveBindingElement(host, node, value, location, /*skipInitializer*/ isDestructuringAssignment(node)); + flattenBindingOrAssignmentElement(host, node, value, location, /*skipInitializer*/ isDestructuringAssignment(node)); if (value && needsValue) { expressions.push(value); @@ -164,7 +105,7 @@ namespace ts { expressions.push(expression); } - function emitBindingOrAssignment(target: EffectiveBindingOrAssignmentTarget, value: Expression, location: TextRange, original: Node) { + function emitBindingOrAssignment(target: BindingOrAssignmentElementTarget, value: Expression, location: TextRange, original: Node) { Debug.assertNode(target, createAssignmentCallback ? isIdentifier : isExpression); const expression = createAssignmentCallback ? createAssignmentCallback(target, value, location) @@ -183,7 +124,7 @@ namespace ts { * @param recordTempVariablesInLine Indicates whether temporary variables should be recored in-line. * @param level Indicates the extent to which flattening should occur. */ - export function flattenDestructuringToDeclarations( + export function flattenDestructuringBinding( context: TransformationContext, node: VariableDeclaration | ParameterDeclaration, boundValue: Expression | undefined, @@ -201,13 +142,13 @@ namespace ts { recordTempVariablesInLine, emitExpression, emitBindingOrAssignment, - createArrayBindingOrAssignmentPattern: createEffectiveArrayBindingPattern, - createObjectBindingOrAssignmentPattern: createEffectiveObjectBindingPattern, - createArrayBindingOrAssignmentElement: createEffectiveBindingElement, + createArrayBindingOrAssignmentPattern: makeArrayBindingPattern, + createObjectBindingOrAssignmentPattern: makeObjectBindingPattern, + createArrayBindingOrAssignmentElement: makeBindingElement, visitor }; - flattenEffectiveBindingElement(host, node, boundValue, node, skipInitializer); + flattenBindingOrAssignmentElement(host, node, boundValue, node, skipInitializer); if (pendingExpressions) { const temp = createTempVariable(/*recordTempVariable*/ undefined); @@ -248,7 +189,7 @@ namespace ts { pendingExpressions = append(pendingExpressions, value); } - function emitBindingOrAssignment(target: EffectiveBindingOrAssignmentTarget, value: Expression, location: TextRange, original: Node) { + function emitBindingOrAssignment(target: BindingOrAssignmentElementTarget, value: Expression, location: TextRange, original: Node) { Debug.assertNode(target, isBindingName); if (pendingExpressions) { value = inlineExpressions(append(pendingExpressions, value)); @@ -258,14 +199,14 @@ namespace ts { } } - function flattenEffectiveBindingElement( + function flattenBindingOrAssignmentElement( host: FlattenHost, - bindingElement: EffectiveBindingOrAssignmentElement, + bindingElement: BindingOrAssignmentElement, boundValue: Expression | undefined, location: TextRange, skipInitializer?: boolean) { if (!skipInitializer) { - const initializer = visitNode(getInitializerOfEffectiveBindingElement(bindingElement), host.visitor, isExpression); + const initializer = visitNode(getInitializerOfBindingOrAssignmentElement(bindingElement), host.visitor, isExpression); if (initializer) { // Combine value and initializer boundValue = boundValue ? createDefaultValueCheck(host, boundValue, initializer, location) : initializer; @@ -275,39 +216,36 @@ namespace ts { boundValue = createVoidZero(); } } - const bindingTarget = getTargetOfEffectiveBindingElement(bindingElement); - if (!isEffectiveBindingPattern(bindingTarget)) { - host.emitBindingOrAssignment(bindingTarget, boundValue, location, /*original*/ bindingElement); + const bindingTarget = getTargetOfBindingOrAssignmentElement(bindingElement); + if (isObjectBindingOrAssignmentPattern(bindingTarget)) { + flattenObjectBindingOrAssignmentPattern(host, bindingElement, bindingTarget, boundValue, location); + } + else if (isArrayBindingOrAssignmentPattern(bindingTarget)) { + flattenArrayBindingOrAssignmentPattern(host, bindingElement, bindingTarget, boundValue, location); } else { - const elements = getElementsOfEffectiveBindingPattern(bindingTarget); - const numElements = elements.length; - if (numElements !== 1) { - // For anything other than a single-element destructuring we need to generate a temporary - // to ensure value is evaluated exactly once. Additionally, if we have zero elements - // we need to emit *something* to ensure that in case a 'var' keyword was already emitted, - // so in that case, we'll intentionally create that temporary. - const reuseIdentifierExpressions = !isDeclarationBindingElement(bindingElement) || numElements !== 0; - boundValue = ensureIdentifier(host, boundValue, reuseIdentifierExpressions, location); - } - if (isEffectiveObjectBindingPattern(bindingTarget)) { - flattenEffectiveObjectBindingElements(host, bindingTarget, elements, boundValue, location); - } - else { - flattenEffectiveArrayBindingElements(host, bindingTarget, elements, boundValue, location); - } + host.emitBindingOrAssignment(bindingTarget, boundValue, location, /*original*/ bindingElement); } } - function flattenEffectiveObjectBindingElements(host: FlattenHost, bindingTarget: EffectiveObjectBindingOrAssignmentPattern, elements: EffectiveBindingOrAssignmentElement[], boundValue: Expression, location: TextRange) { - let bindingElements: EffectiveBindingOrAssignmentElement[]; + function flattenObjectBindingOrAssignmentPattern(host: FlattenHost, parentElement: BindingOrAssignmentElement, bindingTarget: ObjectBindingOrAssignmentPattern, boundValue: Expression, location: TextRange) { + const elements = getElementsOfBindingOrAssignmentPattern(bindingTarget); const numElements = elements.length; + if (numElements !== 1) { + // For anything other than a single-element destructuring we need to generate a temporary + // to ensure value is evaluated exactly once. Additionally, if we have zero elements + // we need to emit *something* to ensure that in case a 'var' keyword was already emitted, + // so in that case, we'll intentionally create that temporary. + const reuseIdentifierExpressions = !isDeclarationBindingElement(parentElement) || numElements !== 0; + boundValue = ensureIdentifier(host, boundValue, reuseIdentifierExpressions, location); + } + let bindingElements: BindingOrAssignmentElement[]; for (let i = 0; i < numElements; i++) { const element = elements[i]; - if (!getEffectiveRestIndicator(element)) { - if (host.level <= FlattenLevel.ObjectRest + if (!getRestIndicatorOfBindingOrAssignmentElement(element)) { + if (host.level >= FlattenLevel.ObjectRest && !(element.transformFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)) - && !(getTargetOfEffectiveBindingElement(element).transformFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest))) { + && !(getTargetOfBindingOrAssignmentElement(element).transformFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest))) { bindingElements = append(bindingElements, element); } else { @@ -315,9 +253,9 @@ namespace ts { host.emitBindingOrAssignment(host.createObjectBindingOrAssignmentPattern(bindingElements), boundValue, location, bindingTarget); bindingElements = undefined; } - const propertyName = getEffectivePropertyNameOfEffectiveBindingElement(element); + const propertyName = getPropertyNameOfBindingOrAssignmentElement(element); const value = createDestructuringPropertyAccess(host, boundValue, propertyName); - flattenEffectiveBindingElement(host, element, value, /*location*/ element); + flattenBindingOrAssignmentElement(host, element, value, /*location*/ element); } } else if (i === numElements - 1) { @@ -326,7 +264,7 @@ namespace ts { bindingElements = undefined; } const value = createRestCall(boundValue, elements, bindingTarget); - flattenEffectiveBindingElement(host, element, value, element); + flattenBindingOrAssignmentElement(host, element, value, element); } } if (bindingElements) { @@ -334,16 +272,27 @@ namespace ts { } } - function flattenEffectiveArrayBindingElements(host: FlattenHost, bindingTarget: EffectiveArrayBindingOrAssignmentPattern, elements: EffectiveBindingOrAssignmentElement[], boundValue: Expression, location: TextRange) { - let bindingElements: EffectiveBindingOrAssignmentElement[]; - let spreadContainingElements: [Identifier, EffectiveBindingOrAssignmentElement][]; + function flattenArrayBindingOrAssignmentPattern(host: FlattenHost, parentElement: BindingOrAssignmentElement, bindingTarget: ArrayBindingOrAssignmentPattern, boundValue: Expression, location: TextRange) { + const elements = getElementsOfBindingOrAssignmentPattern(bindingTarget); const numElements = elements.length; + if (numElements !== 1 && (host.level < FlattenLevel.ObjectRest || numElements === 0)) { + // For anything other than a single-element destructuring we need to generate a temporary + // to ensure value is evaluated exactly once. Additionally, if we have zero elements + // we need to emit *something* to ensure that in case a 'var' keyword was already emitted, + // so in that case, we'll intentionally create that temporary. + const reuseIdentifierExpressions = !isDeclarationBindingElement(parentElement) || numElements !== 0; + boundValue = ensureIdentifier(host, boundValue, reuseIdentifierExpressions, location); + } + let bindingElements: BindingOrAssignmentElement[]; + let restContainingElements: [Identifier, BindingOrAssignmentElement][]; for (let i = 0; i < numElements; i++) { const element = elements[i]; - if (host.level <= FlattenLevel.ObjectRest) { - if (element.transformFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest) && i < numElements - 1) { + if (host.level >= FlattenLevel.ObjectRest) { + // If an array pattern contains an ObjectRest, we must cache the result so that we + // can perform the ObjectRest destructuring in a different declaration + if (element.transformFlags & TransformFlags.ContainsObjectRest) { const temp = createTempVariable(/*recordTempVariable*/ undefined); - spreadContainingElements = append(spreadContainingElements, <[Identifier, EffectiveBindingOrAssignmentElement]>[temp, element]); + restContainingElements = append(restContainingElements, <[Identifier, BindingOrAssignmentElement]>[temp, element]); bindingElements = append(bindingElements, host.createArrayBindingOrAssignmentElement(temp)); } else { @@ -353,21 +302,21 @@ namespace ts { else if (isOmittedExpression(element)) { continue; } - else if (!getEffectiveRestIndicator(element)) { + else if (!getRestIndicatorOfBindingOrAssignmentElement(element)) { const value = createElementAccess(boundValue, i); - flattenEffectiveBindingElement(host, element, value, /*location*/ element); + flattenBindingOrAssignmentElement(host, element, value, /*location*/ element); } else if (i === numElements - 1) { const value = createArraySlice(boundValue, i); - flattenEffectiveBindingElement(host, element, value, /*location*/ element); + flattenBindingOrAssignmentElement(host, element, value, /*location*/ element); } } if (bindingElements) { host.emitBindingOrAssignment(host.createArrayBindingOrAssignmentPattern(bindingElements), boundValue, location, bindingTarget); } - if (spreadContainingElements) { - for (const [id, element] of spreadContainingElements) { - flattenEffectiveBindingElement(host, element, id, element); + if (restContainingElements) { + for (const [id, element] of restContainingElements) { + flattenBindingOrAssignmentElement(host, element, id, element); } } } @@ -448,321 +397,35 @@ namespace ts { } } - /** - * Determines whether the EffectiveBindingElement is a declaration - */ - function isDeclarationBindingElement(bindingElement: EffectiveBindingOrAssignmentElement): bindingElement is VariableDeclaration | ParameterDeclaration | BindingElement { - switch (bindingElement.kind) { - case SyntaxKind.VariableDeclaration: - case SyntaxKind.Parameter: - case SyntaxKind.BindingElement: - return true; - } - - return false; - } - - /** - * Gets the initializer of an EffectiveBindingElement. - */ - function getInitializerOfEffectiveBindingElement(bindingElement: EffectiveBindingOrAssignmentElement): Expression | undefined { - if (isDeclarationBindingElement(bindingElement)) { - // `1` in `let { a = 1 } = ...` - // `1` in `let { a: b = 1 } = ...` - // `1` in `let { a: {b} = 1 } = ...` - // `1` in `let { a: [b] = 1 } = ...` - // `1` in `let [a = 1] = ...` - // `1` in `let [{a} = 1] = ...` - // `1` in `let [[a] = 1] = ...` - return bindingElement.initializer; - } - - if (isPropertyAssignment(bindingElement)) { - // `1` in `({ a: b = 1 } = ...)` - // `1` in `({ a: {b} = 1 } = ...)` - // `1` in `({ a: [b] = 1 } = ...)` - return isAssignmentExpression(bindingElement.initializer, /*excludeCompoundAssignment*/ true) - ? bindingElement.initializer.right - : undefined; - } - - if (isShorthandPropertyAssignment(bindingElement)) { - // `1` in `({ a = 1 } = ...)` - return bindingElement.objectAssignmentInitializer; - } - - if (isAssignmentExpression(bindingElement, /*excludeCompoundAssignment*/ true)) { - // `1` in `[a = 1] = ...` - // `1` in `[{a} = 1] = ...` - // `1` in `[[a] = 1] = ...` - return bindingElement.right; - } - - if (isSpreadExpression(bindingElement) || isPartiallyEmittedExpression(bindingElement)) { - // Recovery consistent with existing emit. - return getInitializerOfEffectiveBindingElement(bindingElement.expression); - } - } - - /** - * Gets the name of an EffectiveBindingElement. - */ - function getTargetOfEffectiveBindingElement(bindingElement: EffectiveBindingOrAssignmentElement): EffectiveBindingOrAssignmentTarget { - if (isDeclarationBindingElement(bindingElement)) { - // `a` in `let { a } = ...` - // `a` in `let { a = 1 } = ...` - // `b` in `let { a: b } = ...` - // `b` in `let { a: b = 1 } = ...` - // `a` in `let { ...a } = ...` - // `{b}` in `let { a: {b} } = ...` - // `{b}` in `let { a: {b} = 1 } = ...` - // `[b]` in `let { a: [b] } = ...` - // `[b]` in `let { a: [b] = 1 } = ...` - // `a` in `let [a] = ...` - // `a` in `let [a = 1] = ...` - // `a` in `let [...a] = ...` - // `{a}` in `let [{a}] = ...` - // `{a}` in `let [{a} = 1] = ...` - // `[a]` in `let [[a]] = ...` - // `[a]` in `let [[a] = 1] = ...` - return bindingElement.name; - } - - if (isObjectLiteralElementLike(bindingElement)) { - switch (bindingElement.kind) { - case SyntaxKind.PropertyAssignment: - // `b` in `({ a: b } = ...)` - // `b` in `({ a: b = 1 } = ...)` - // `{b}` in `({ a: {b} } = ...)` - // `{b}` in `({ a: {b} = 1 } = ...)` - // `[b]` in `({ a: [b] } = ...)` - // `[b]` in `({ a: [b] = 1 } = ...)` - // `b.c` in `({ a: b.c } = ...)` - // `b.c` in `({ a: b.c = 1 } = ...)` - // `b[0]` in `({ a: b[0] } = ...)` - // `b[0]` in `({ a: b[0] = 1 } = ...)` - return getTargetOfEffectiveBindingElement(bindingElement.initializer); - - case SyntaxKind.ShorthandPropertyAssignment: - // `a` in `({ a } = ...)` - // `a` in `({ a = 1 } = ...)` - return bindingElement.name; - - case SyntaxKind.SpreadAssignment: - // `a` in `({ ...a } = ...)` - return getTargetOfEffectiveBindingElement(bindingElement.expression); - } - - // no target - return undefined; - } - - if (isAssignmentExpression(bindingElement, /*excludeCompoundAssignment*/ true)) { - // `a` in `[a = 1] = ...` - // `{a}` in `[{a} = 1] = ...` - // `[a]` in `[[a] = 1] = ...` - // `a.b` in `[a.b = 1] = ...` - // `a[0]` in `[a[0] = 1] = ...` - return getTargetOfEffectiveBindingElement(bindingElement.left); - } - - if (isSpreadExpression(bindingElement) || isPartiallyEmittedExpression(bindingElement)) { - // `a` in `[...a] = ...` - return getTargetOfEffectiveBindingElement(bindingElement.expression); - } - - // `a` in `[a] = ...` - // `{a}` in `[{a}] = ...` - // `[a]` in `[[a]] = ...` - // `a.b` in `[a.b] = ...` - // `a[0]` in `[a[0]] = ...` - return bindingElement; - } - - /** - * Determines whether an EffectiveBindingElement is a rest element. - */ - function getEffectiveRestIndicator(bindingElement: EffectiveBindingOrAssignmentElement): EffectiveBindingOrAssignmentRestIndicator { - switch (bindingElement.kind) { - case SyntaxKind.Parameter: - case SyntaxKind.BindingElement: - // `...` in `let [...a] = ...` - return (bindingElement).dotDotDotToken; - - case SyntaxKind.SpreadElement: - case SyntaxKind.SpreadAssignment: - // `...` in `[...a] = ...` - return bindingElement; - } - - return undefined; - } - - /** - * Gets the property name of a BindingElement-like element - */ - function getEffectivePropertyNameOfEffectiveBindingElement(bindingElement: EffectiveBindingOrAssignmentElement) { - switch (bindingElement.kind) { - case SyntaxKind.BindingElement: - // `a` in `let { a: b } = ...` - // `[a]` in `let { [a]: b } = ...` - // `"a"` in `let { "a": b } = ...` - // `1` in `let { 1: b } = ...` - if ((bindingElement).propertyName) { - return (bindingElement).propertyName; - } - - break; - - case SyntaxKind.PropertyAssignment: - // `a` in `({ a: b } = ...)` - // `[a]` in `({ [a]: b } = ...)` - // `"a"` in `({ "a": b } = ...)` - // `1` in `({ 1: b } = ...)` - if ((bindingElement).name) { - return (bindingElement).name; - } - - break; - - case SyntaxKind.SpreadAssignment: - // `a` in `({ ...a } = ...)` - return (bindingElement).name; - } - - const target = getTargetOfEffectiveBindingElement(bindingElement); - if (target && isPropertyName(target)) { - return target; - } - - Debug.fail("Invalid property name for binding element."); - } - - /** - * Determines whether a node is BindingPattern-like - */ - function isEffectiveBindingPattern(node: EffectiveBindingOrAssignmentTarget): node is EffectiveBindingOrAssignmentPattern { - return isEffectiveObjectBindingPattern(node) - || isEffectiveArrayBindingPattern(node); - } - - /** - * Determines whether a node is ObjectBindingPattern-like - */ - function isEffectiveObjectBindingPattern(node: EffectiveBindingOrAssignmentTarget): node is EffectiveObjectBindingOrAssignmentPattern { - switch (node.kind) { - case SyntaxKind.ObjectBindingPattern: - case SyntaxKind.ObjectLiteralExpression: - return true; - } - - return false; - } - - /** - * Determines whether a node is ArrayBindingPattern-like - */ - function isEffectiveArrayBindingPattern(node: EffectiveBindingOrAssignmentTarget): node is EffectiveArrayBindingOrAssignmentPattern { - switch (node.kind) { - case SyntaxKind.ArrayBindingPattern: - case SyntaxKind.ArrayLiteralExpression: - return true; - } - - return false; - } - - /** - * Gets the elements of a BindingPattern-like name - */ - function getElementsOfEffectiveBindingPattern(name: EffectiveBindingOrAssignmentPattern): EffectiveBindingOrAssignmentElement[] { - switch (name.kind) { - case SyntaxKind.ObjectBindingPattern: - case SyntaxKind.ArrayBindingPattern: - case SyntaxKind.ArrayLiteralExpression: - // `a` in `{a}` - // `a` in `[a]` - return name.elements; - - case SyntaxKind.ObjectLiteralExpression: - // `a` in `{a}` - return name.properties; - } - } - - function createEffectiveArrayBindingPattern(elements: EffectiveBindingOrAssignmentElement[]) { + function makeArrayBindingPattern(elements: BindingOrAssignmentElement[]) { Debug.assertEachNode(elements, isArrayBindingElement); return createArrayBindingPattern(elements); } - function createEffectiveArrayAssignmentPattern(elements: EffectiveBindingOrAssignmentElement[]) { - return createArrayLiteral(map(elements, convertToArrayLiteralElement)); + function makeArrayAssignmentPattern(elements: BindingOrAssignmentElement[]) { + return createArrayLiteral(map(elements, convertToArrayAssignmentElement)); } - function createEffectiveObjectBindingPattern(elements: EffectiveBindingOrAssignmentElement[]) { + function makeObjectBindingPattern(elements: BindingOrAssignmentElement[]) { Debug.assertEachNode(elements, isBindingElement); return createObjectBindingPattern(elements); } - function createEffectiveObjectAssignmentPattern(elements: EffectiveBindingOrAssignmentElement[]) { - return createObjectLiteral(map(elements, convertToObjectLiteralElement)); + function makeObjectAssignmentPattern(elements: BindingOrAssignmentElement[]) { + return createObjectLiteral(map(elements, convertToObjectAssignmentElement)); } - function createEffectiveBindingElement(name: Identifier) { + function makeBindingElement(name: Identifier) { return createBindingElement(/*propertyName*/ undefined, /*dotDotDotToken*/ undefined, name); } - function createEffectiveAssignmentElement(name: Identifier) { + function makeAssignmentElement(name: Identifier) { return name; } - function convertToArrayLiteralElement(element: EffectiveBindingOrAssignmentElement) { - if (isBindingElement(element)) { - if (element.dotDotDotToken) { - Debug.assertNode(element.name, isIdentifier); - return setOriginalNode(createSpread(element.name, element), element); - } - const expression = convertToExpressionTarget(element.name); - return element.initializer ? setOriginalNode(createAssignment(expression, element.initializer, element), element) : expression; - } - Debug.assertNode(element, isExpression); - return element; - } - - function convertToObjectLiteralElement(element: EffectiveBindingOrAssignmentElement) { - if (isBindingElement(element)) { - if (element.dotDotDotToken) { - Debug.assertNode(element.name, isIdentifier); - return setOriginalNode(createSpreadAssignment(element.name, element), element); - } - if (element.propertyName) { - const expression = convertToExpressionTarget(element.name); - return setOriginalNode(createPropertyAssignment(element.propertyName, element.initializer ? createAssignment(expression, element.initializer) : expression, element), element); - } - Debug.assertNode(element.name, isIdentifier); - return setOriginalNode(createShorthandPropertyAssignment(element.name, element.initializer, element), element); - } - Debug.assertNode(element, isObjectLiteralElementLike); - return element; - } - - function convertToExpressionTarget(target: EffectiveBindingOrAssignmentTarget): Expression { - if (isBindingPattern(target)) { - switch (target.kind) { - case SyntaxKind.ArrayBindingPattern: - return setOriginalNode(createArrayLiteral(map(target.elements, convertToArrayLiteralElement), target), target); - case SyntaxKind.ObjectBindingPattern: - return setOriginalNode(createObjectLiteral(map(target.elements, convertToObjectLiteralElement), target), target); - } - return; - } - Debug.assertNode(target, isExpression); - return target; - } - /** Given value: o, propName: p, pattern: { a, b, ...p } from the original statement * `{ a, b, ...p } = o`, create `p = __rest(o, ["a", "b"]);`*/ - function createRestCall(value: Expression, elements: EffectiveBindingOrAssignmentElement[], location: TextRange): Expression { + function createRestCall(value: Expression, elements: BindingOrAssignmentElement[], location: TextRange): Expression { const propertyNames: LiteralExpression[] = []; for (let i = 0; i < elements.length - 1; i++) { if (isOmittedExpression(elements[i])) { @@ -771,7 +434,7 @@ namespace ts { const str = createSynthesizedNode(SyntaxKind.StringLiteral); str.pos = location.pos; str.end = location.end; - str.text = getTextOfPropertyName(getEffectivePropertyNameOfEffectiveBindingElement(elements[i])); + str.text = getTextOfPropertyName(getPropertyNameOfBindingOrAssignmentElement(elements[i])); propertyNames.push(str); } const args = createSynthesizedNodeArray([value, createArrayLiteral(propertyNames, location)]); diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index dd7498c4149..29107e149f4 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -1365,7 +1365,7 @@ namespace ts { function visitBinaryExpression(node: BinaryExpression, needsDestructuringValue: boolean): Expression { // If we are here it is because this is a destructuring assignment. Debug.assert(isDestructuringAssignment(node)); - return flattenDestructuringToExpression( + return flattenDestructuringAssignment( context, node, needsDestructuringValue, @@ -1383,7 +1383,7 @@ namespace ts { if (decl.initializer) { let assignment: Expression; if (isBindingPattern(decl.name)) { - assignment = flattenDestructuringToExpression( + assignment = flattenDestructuringAssignment( context, decl, /*needsValue*/ false, @@ -1543,8 +1543,7 @@ namespace ts { if (isBindingPattern(node.name)) { const recordTempVariablesInLine = !enclosingVariableStatement || !hasModifier(enclosingVariableStatement, ModifierFlags.Export); - debugger; - return flattenDestructuringToDeclarations( + return flattenDestructuringBinding( context, node, /*value*/ undefined, @@ -2181,7 +2180,7 @@ namespace ts { const temp = createTempVariable(undefined); const newVariableDeclaration = createVariableDeclaration(temp, undefined, undefined, node.variableDeclaration); - const vars = flattenDestructuringToDeclarations(context, node.variableDeclaration, temp, /*skipInitializer*/ false, /*recordTempVariablesInLine*/ true, FlattenLevel.All, visitor); + const vars = flattenDestructuringBinding(context, node.variableDeclaration, temp, /*skipInitializer*/ false, /*recordTempVariablesInLine*/ true, FlattenLevel.All, visitor); const list = createVariableDeclarationList(vars, /*location*/node.variableDeclaration, /*flags*/node.variableDeclaration.flags); const destructure = createVariableStatement(undefined, list); diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index a52ee9b1a24..fb854318e69 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -135,7 +135,7 @@ namespace ts { */ function visitBinaryExpression(node: BinaryExpression, needsDestructuringValue: boolean): Expression { if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.ContainsESNext) { - return flattenDestructuringToExpression( + return flattenDestructuringAssignment( context, node, needsDestructuringValue, @@ -156,7 +156,7 @@ namespace ts { function visitVariableDeclaration(node: VariableDeclaration): VisitResult { // If we are here it is because the name contains a binding pattern with a rest somewhere in it. if (isBindingPattern(node.name) && node.name.transformFlags & TransformFlags.AssertESNext) { - return flattenDestructuringToDeclarations(context, node, /*boundValue*/ undefined, /*skipInitializer*/ false, /*recordTempVariablesInLine*/ true, FlattenLevel.ObjectRest, visitor); + return flattenDestructuringBinding(context, node, /*boundValue*/ undefined, /*skipInitializer*/ false, /*recordTempVariablesInLine*/ true, FlattenLevel.ObjectRest, visitor); } return visitEachChild(node, visitor, context); } @@ -202,14 +202,14 @@ namespace ts { const declaration = firstOrUndefined(initializer.declarations); return declaration && declaration.name && declaration.name.kind === SyntaxKind.ObjectBindingPattern && - !!(declaration.name.transformFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)); + !!(declaration.name.transformFlags & TransformFlags.ContainsObjectRest); } return false; } function isRestAssignment(initializer: ForInitializer) { return initializer.kind === SyntaxKind.ObjectLiteralExpression && - initializer.transformFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest); + initializer.transformFlags & TransformFlags.ContainsObjectRest; } function visitParameter(node: ParameterDeclaration): ParameterDeclaration { @@ -238,7 +238,7 @@ namespace ts { function isObjectRestParameter(node: ParameterDeclaration) { return node.name && node.name.kind === SyntaxKind.ObjectBindingPattern && - !!(node.name.transformFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)); + !!(node.name.transformFlags & TransformFlags.ContainsObjectRest); } function visitFunctionDeclaration(node: FunctionDeclaration): FunctionDeclaration { diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index bb17b99e5c6..8c65630aa5c 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -756,7 +756,7 @@ namespace ts { */ function transformInitializedVariable(node: VariableDeclaration): Expression { if (isBindingPattern(node.name)) { - return flattenDestructuringToExpression( + return flattenDestructuringAssignment( context, node, /*needsValue*/ false, diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index 1ed1f82d506..3d89305f617 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -808,7 +808,7 @@ namespace ts { function transformInitializedVariable(node: VariableDeclaration, isExportedDeclaration: boolean): Expression { const createAssignment = isExportedDeclaration ? createExportedVariableAssignment : createNonExportedVariableAssignment; return isBindingPattern(node.name) - ? flattenDestructuringToExpression(context, node, /*needsValue*/ false, FlattenLevel.All, createAssignment, destructuringVisitor) + ? flattenDestructuringAssignment(context, node, /*needsValue*/ false, FlattenLevel.All, createAssignment, destructuringVisitor) : createAssignment(node.name, visitNode(node.initializer, destructuringVisitor, isExpression)); } @@ -1459,7 +1459,7 @@ namespace ts { */ function visitDestructuringAssignment(node: DestructuringAssignment): VisitResult { if (hasExportedReferenceInDestructuringTarget(node.left)) { - return flattenDestructuringToExpression( + return flattenDestructuringAssignment( context, node, /*needsValue*/ true, diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 118b170b6a4..4fc68566795 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -2353,7 +2353,7 @@ namespace ts { function transformInitializedVariable(node: VariableDeclaration): Expression { const name = node.name; if (isBindingPattern(name)) { - return flattenDestructuringToExpression( + return flattenDestructuringAssignment( context, node, /*needsValue*/ false, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e0ba546fb96..0cda729f998 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -722,22 +722,20 @@ namespace ts { name: PropertyName; } - export interface BindingPattern extends Node { - elements: NodeArray; - } - - export interface ObjectBindingPattern extends BindingPattern { + export interface ObjectBindingPattern extends Node { kind: SyntaxKind.ObjectBindingPattern; elements: NodeArray; } - export type ArrayBindingElement = BindingElement | OmittedExpression; - - export interface ArrayBindingPattern extends BindingPattern { + export interface ArrayBindingPattern extends Node { kind: SyntaxKind.ArrayBindingPattern; elements: NodeArray; } + export type BindingPattern = (ObjectBindingPattern | ArrayBindingPattern) & { elements: NodeArray; }; + + export type ArrayBindingElement = BindingElement | OmittedExpression; + /** * Several node kinds share function-like features such as a signature, * a name, and a body. These nodes should extend FunctionLikeDeclaration. @@ -1191,7 +1189,49 @@ namespace ts { left: ArrayLiteralExpression; } - export type DestructuringAssignment = ObjectDestructuringAssignment | ArrayDestructuringAssignment; + export type DestructuringAssignment + = ObjectDestructuringAssignment + | ArrayDestructuringAssignment + ; + + export type BindingOrAssignmentElement + = VariableDeclaration + | ParameterDeclaration + | BindingElement + | PropertyAssignment // AssignmentProperty + | ShorthandPropertyAssignment // AssignmentProperty + | SpreadAssignment // AssignmentRestProperty + | OmittedExpression // Elision + | SpreadElement // AssignmentRestElement + | ArrayLiteralExpression // ArrayAssignmentPattern + | ObjectLiteralExpression // ObjectAssignmentPattern + | AssignmentExpression // AssignmentElement + | Identifier // DestructuringAssignmentTarget + | PropertyAccessExpression // DestructuringAssignmentTarget + | ElementAccessExpression // DestructuringAssignmentTarget + ; + + export type BindingOrAssignmentElementRestIndicator + = DotDotDotToken // from BindingElement + | SpreadElement // AssignmentRestElement + | SpreadAssignment // AssignmentRestProperty + ; + + export type BindingOrAssignmentElementTarget = BindingOrAssignmentPattern | Expression; + + export type ObjectBindingOrAssignmentPattern + = ObjectBindingPattern + | ObjectLiteralExpression // ObjectAssignmentPattern + ; + + export type ArrayBindingOrAssignmentPattern + = ArrayBindingPattern + | ArrayLiteralExpression // ArrayAssignmentPattern + ; + + export type AssignmentPattern = ObjectLiteralExpression | ArrayLiteralExpression; + + export type BindingOrAssignmentPattern = ObjectBindingOrAssignmentPattern | ArrayBindingOrAssignmentPattern; export interface ConditionalExpression extends Expression { kind: SyntaxKind.ConditionalExpression; @@ -3554,10 +3594,10 @@ namespace ts { TypeExcludes = ~ContainsTypeScript, ObjectLiteralExcludes = NodeExcludes | ContainsDecorators | ContainsComputedPropertyName | ContainsLexicalThisInComputedPropertyName | ContainsObjectSpread, ArrayLiteralOrCallOrNewExcludes = NodeExcludes | ContainsSpread, - VariableDeclarationListExcludes = NodeExcludes | ContainsBindingPattern | ContainsObjectSpread, + VariableDeclarationListExcludes = NodeExcludes | ContainsBindingPattern | ContainsObjectRest, ParameterExcludes = NodeExcludes, - CatchClauseExcludes = NodeExcludes | ContainsObjectSpread, - BindingPatternExcludes = NodeExcludes | ContainsSpread, + CatchClauseExcludes = NodeExcludes | ContainsObjectRest, + BindingPatternExcludes = NodeExcludes | ContainsRest, // Masks // - Additional bitmasks diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index f0a666e1531..669b0d542ac 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3948,6 +3948,78 @@ namespace ts { || kind === SyntaxKind.OmittedExpression; } + + /** + * Determines whether the BindingOrAssignmentElement is a BindingElement-like declaration + */ + export function isDeclarationBindingElement(bindingElement: BindingOrAssignmentElement): bindingElement is VariableDeclaration | ParameterDeclaration | BindingElement { + switch (bindingElement.kind) { + case SyntaxKind.VariableDeclaration: + case SyntaxKind.Parameter: + case SyntaxKind.BindingElement: + return true; + } + + return false; + } + + /** + * Determines whether a node is a BindingOrAssignmentElement + */ + export function isBindingOrAssignmentElement(node: Node): node is BindingOrAssignmentElement { + switch (node.kind) { + case SyntaxKind.VariableDeclaration: + case SyntaxKind.Parameter: + case SyntaxKind.BindingElement: + case SyntaxKind.PropertyAssignment: + case SyntaxKind.ShorthandPropertyAssignment: + case SyntaxKind.SpreadAssignment: + case SyntaxKind.OmittedExpression: + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.PropertyAccessExpression: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.Identifier: + case SyntaxKind.SpreadElement: + return true; + } + return isAssignmentExpression(node, /*excludeCompoundAssignment*/ true); + } + + /** + * Determines whether a node is a BindingOrAssignmentPattern + */ + export function isBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is BindingOrAssignmentPattern { + return isObjectBindingOrAssignmentPattern(node) + || isArrayBindingOrAssignmentPattern(node); + } + + /** + * Determines whether a node is an ObjectBindingOrAssignmentPattern + */ + export function isObjectBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is ObjectBindingOrAssignmentPattern { + switch (node.kind) { + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ObjectLiteralExpression: + return true; + } + + return false; + } + + /** + * Determines whether a node is an ArrayBindingOrAssignmentPattern + */ + export function isArrayBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is ArrayBindingOrAssignmentPattern { + switch (node.kind) { + case SyntaxKind.ArrayBindingPattern: + case SyntaxKind.ArrayLiteralExpression: + return true; + } + + return false; + } + // Expression export function isArrayLiteralExpression(node: Node): node is ArrayLiteralExpression { From 60d5195112ee7ab80ba01a3fbd874b7566158c01 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 14 Nov 2016 16:56:59 -0800 Subject: [PATCH 04/10] Update baselines, fix assignment check for object rest. --- Jakefile.js | 2 +- src/compiler/checker.ts | 6 ++-- src/compiler/diagnosticMessages.json | 2 +- src/compiler/factory.ts | 28 ++++++------------- src/compiler/transformers/destructuring.ts | 4 +++ src/compiler/types.ts | 2 +- src/compiler/utilities.ts | 23 --------------- src/harness/runner.ts | 4 +++ .../reference/objectRestAssignment.js | 6 ++-- .../reference/objectRestNegative.errors.txt | 4 +-- .../baselines/reference/objectRestNegative.js | 2 +- 11 files changed, 27 insertions(+), 56 deletions(-) diff --git a/Jakefile.js b/Jakefile.js index 2e5d660c4f1..132a99e5087 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -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"); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 396715bfa45..730a435e67f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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); } } @@ -14199,9 +14199,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); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index be33335021b..a163a3bb641 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -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 }, diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index c107263b9d8..d690eb84c78 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -3284,9 +3284,9 @@ namespace ts { return bindingElement.right; } - if (isSpreadExpression(bindingElement) && isBindingOrAssignmentElement(bindingElement.expression)) { + if (isSpreadExpression(bindingElement)) { // Recovery consistent with existing emit. - return getInitializerOfBindingOrAssignmentElement(bindingElement.expression); + return getInitializerOfBindingOrAssignmentElement(bindingElement.expression); } } @@ -3327,9 +3327,7 @@ namespace ts { // `b.c` in `({ a: b.c = 1 } = ...)` // `b[0]` in `({ a: b[0] } = ...)` // `b[0]` in `({ a: b[0] = 1 } = ...)` - return isBindingOrAssignmentElement(bindingElement.initializer) - ? getTargetOfBindingOrAssignmentElement(bindingElement.initializer) - : undefined; + return getTargetOfBindingOrAssignmentElement(bindingElement.initializer); case SyntaxKind.ShorthandPropertyAssignment: // `a` in `({ a } = ...)` @@ -3338,9 +3336,7 @@ namespace ts { case SyntaxKind.SpreadAssignment: // `a` in `({ ...a } = ...)` - return isBindingOrAssignmentElement(bindingElement.expression) - ? getTargetOfBindingOrAssignmentElement(bindingElement.expression) - : undefined; + return getTargetOfBindingOrAssignmentElement(bindingElement.expression); } // no target @@ -3353,16 +3349,12 @@ namespace ts { // `[a]` in `[[a] = 1] = ...` // `a.b` in `[a.b = 1] = ...` // `a[0]` in `[a[0] = 1] = ...` - return isBindingOrAssignmentElement(bindingElement.left) - ? getTargetOfBindingOrAssignmentElement(bindingElement.left) - : undefined; + return getTargetOfBindingOrAssignmentElement(bindingElement.left); } if (isSpreadExpression(bindingElement)) { // `a` in `[...a] = ...` - return isBindingOrAssignmentElement(bindingElement.expression) - ? getTargetOfBindingOrAssignmentElement(bindingElement.expression) - : undefined; + return getTargetOfBindingOrAssignmentElement(bindingElement.expression); } // `a` in `[a] = ...` @@ -3442,18 +3434,14 @@ namespace ts { case SyntaxKind.ArrayLiteralExpression: // `a` in `{a}` // `a` in `[a]` - return map(name.elements, convertToBindingOrAssignmentElement); + return name.elements; case SyntaxKind.ObjectLiteralExpression: // `a` in `{a}` - return filter(name.properties, isBindingOrAssignmentElement); + return name.properties; } } - function convertToBindingOrAssignmentElement(node: Node) { - return isBindingOrAssignmentElement(node) ? node : createOmittedExpression(node); - } - export function convertToArrayAssignmentElement(element: BindingOrAssignmentElement) { if (isBindingElement(element)) { if (element.dotDotDotToken) { diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index b8da29ae291..433305ca6b2 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -292,6 +292,10 @@ namespace ts { // can perform the ObjectRest destructuring in a different declaration if (element.transformFlags & TransformFlags.ContainsObjectRest) { const temp = createTempVariable(/*recordTempVariable*/ undefined); + if (!host.recordTempVariablesInLine) { + host.context.hoistVariableDeclaration(temp); + } + restContainingElements = append(restContainingElements, <[Identifier, BindingOrAssignmentElement]>[temp, element]); bindingElements = append(bindingElements, host.createArrayBindingOrAssignmentElement(temp)); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 52b8eeb0fd3..8a6e74030d5 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -734,7 +734,7 @@ namespace ts { elements: NodeArray; } - export type BindingPattern = (ObjectBindingPattern | ArrayBindingPattern) & { elements: NodeArray; }; + export type BindingPattern = ObjectBindingPattern | ArrayBindingPattern; export type ArrayBindingElement = BindingElement | OmittedExpression; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 52efb88f8c5..317cad49def 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3975,29 +3975,6 @@ namespace ts { return false; } - /** - * Determines whether a node is a BindingOrAssignmentElement - */ - export function isBindingOrAssignmentElement(node: Node): node is BindingOrAssignmentElement { - switch (node.kind) { - case SyntaxKind.VariableDeclaration: - case SyntaxKind.Parameter: - case SyntaxKind.BindingElement: - case SyntaxKind.PropertyAssignment: - case SyntaxKind.ShorthandPropertyAssignment: - case SyntaxKind.SpreadAssignment: - case SyntaxKind.OmittedExpression: - case SyntaxKind.ArrayLiteralExpression: - case SyntaxKind.ObjectLiteralExpression: - case SyntaxKind.PropertyAccessExpression: - case SyntaxKind.ElementAccessExpression: - case SyntaxKind.Identifier: - case SyntaxKind.SpreadElement: - return true; - } - return isAssignmentExpression(node, /*excludeCompoundAssignment*/ true); - } - /** * Determines whether a node is a BindingOrAssignmentPattern */ diff --git a/src/harness/runner.ts b/src/harness/runner.ts index 3db1da627bc..3ad6269e52f 100644 --- a/src/harness/runner.ts +++ b/src/harness/runner.ts @@ -61,6 +61,10 @@ function createRunner(kind: TestRunnerKind): RunnerBase { } } +if (Harness.IO.tryEnableSourceMapsForHost && /^development$/i.test(Harness.IO.getEnvironmentVariable("NODE_ENV"))) { + Harness.IO.tryEnableSourceMapsForHost(); +} + // users can define tests to run in mytest.config that will override cmd line args, otherwise use cmd line args (test.config), otherwise no options const mytestconfigFileName = "mytest.config"; diff --git a/tests/baselines/reference/objectRestAssignment.js b/tests/baselines/reference/objectRestAssignment.js index d4d266d3fe5..50d38c178a9 100644 --- a/tests/baselines/reference/objectRestAssignment.js +++ b/tests/baselines/reference/objectRestAssignment.js @@ -30,6 +30,6 @@ let complex; // should be: let overEmit; // var _g = overEmit.a, [_h, ...y] = _g, nested2 = __rest(_h, []), _j = overEmit.b, { z } = _j, c = __rest(_j, ["z"]), rest2 = __rest(overEmit, ["a", "b"]); -var _b = overEmit.a, [_c, ...y] = _b, nested2 = __rest(_c, []), _d = overEmit.b, { z } = _d, c = __rest(_d, ["z"]), rest2 = __rest(overEmit, ["a", "b"]); -(_e = overEmit.a, [_f, ...y] = _e, nested2 = __rest(_f, []), _g = overEmit.b, { z } = _g, c = __rest(_g, ["z"]), rest2 = __rest(overEmit, ["a", "b"])); -var _a, _e, _g; +var [_b, ...y] = overEmit.a, nested2 = __rest(_b, []), _c = overEmit.b, { z } = _c, c = __rest(_c, ["z"]), rest2 = __rest(overEmit, ["a", "b"]); +([_d, ...y] = overEmit.a, nested2 = __rest(_d, []), _e = overEmit.b, { z } = _e, c = __rest(_e, ["z"]), rest2 = __rest(overEmit, ["a", "b"])); +var _a, _d, _e; diff --git a/tests/baselines/reference/objectRestNegative.errors.txt b/tests/baselines/reference/objectRestNegative.errors.txt index b8144e3209b..793a7d31fc8 100644 --- a/tests/baselines/reference/objectRestNegative.errors.txt +++ b/tests/baselines/reference/objectRestNegative.errors.txt @@ -1,7 +1,7 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(2,10): error TS2462: A rest element must be last in a destructuring pattern tests/cases/conformance/types/rest/objectRestNegative.ts(3,31): error TS2462: A rest element must be last in a destructuring pattern tests/cases/conformance/types/rest/objectRestNegative.ts(6,17): error TS2700: Rest types may only be created from object types. -tests/cases/conformance/types/rest/objectRestNegative.ts(11,9): error TS2701: An object rest element must be an identifier. +tests/cases/conformance/types/rest/objectRestNegative.ts(11,9): error TS2701: The target of an object rest assignment must be a variable or a property access. ==== tests/cases/conformance/types/rest/objectRestNegative.ts (4 errors) ==== @@ -23,5 +23,5 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(11,9): error TS2701: An let rest: { b: string } ({a, ...rest.b + rest.b} = o); ~~~~~~~~~~~~~~~ -!!! error TS2701: An object rest element must be an identifier. +!!! error TS2701: The target of an object rest assignment must be a variable or a property access. \ No newline at end of file diff --git a/tests/baselines/reference/objectRestNegative.js b/tests/baselines/reference/objectRestNegative.js index 76e3cd765db..c9f0dba32c1 100644 --- a/tests/baselines/reference/objectRestNegative.js +++ b/tests/baselines/reference/objectRestNegative.js @@ -29,4 +29,4 @@ function generic(t) { return rest; } var rest; -(a = o.a, o, o); +(a = o.a, o, rest.b + rest.b = __rest(o, ["a"])); From cbdde421e63ce508b1a258ac8fe35d350f5218c8 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 14 Nov 2016 17:06:10 -0800 Subject: [PATCH 05/10] Moved the parenthesizing functions to make the diff easier to read --- src/compiler/factory.ts | 804 ++++++++++++++++++++-------------------- 1 file changed, 401 insertions(+), 403 deletions(-) diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index d690eb84c78..919864628da 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -2424,6 +2424,407 @@ namespace ts { return node; } + /** + * Wraps the operand to a BinaryExpression in parentheses if they are needed to preserve the intended + * order of operations. + * + * @param binaryOperator The operator for the BinaryExpression. + * @param operand The operand for the BinaryExpression. + * @param isLeftSideOfBinary A value indicating whether the operand is the left side of the + * BinaryExpression. + */ + export function parenthesizeBinaryOperand(binaryOperator: SyntaxKind, operand: Expression, isLeftSideOfBinary: boolean, leftOperand?: Expression) { + const skipped = skipPartiallyEmittedExpressions(operand); + + // If the resulting expression is already parenthesized, we do not need to do any further processing. + if (skipped.kind === SyntaxKind.ParenthesizedExpression) { + return operand; + } + + return binaryOperandNeedsParentheses(binaryOperator, operand, isLeftSideOfBinary, leftOperand) + ? createParen(operand) + : operand; + } + + /** + * Determines whether the operand to a BinaryExpression needs to be parenthesized. + * + * @param binaryOperator The operator for the BinaryExpression. + * @param operand The operand for the BinaryExpression. + * @param isLeftSideOfBinary A value indicating whether the operand is the left side of the + * BinaryExpression. + */ + function binaryOperandNeedsParentheses(binaryOperator: SyntaxKind, operand: Expression, isLeftSideOfBinary: boolean, leftOperand: Expression) { + // If the operand has lower precedence, then it needs to be parenthesized to preserve the + // intent of the expression. For example, if the operand is `a + b` and the operator is + // `*`, then we need to parenthesize the operand to preserve the intended order of + // operations: `(a + b) * x`. + // + // If the operand has higher precedence, then it does not need to be parenthesized. For + // example, if the operand is `a * b` and the operator is `+`, then we do not need to + // parenthesize to preserve the intended order of operations: `a * b + x`. + // + // If the operand has the same precedence, then we need to check the associativity of + // the operator based on whether this is the left or right operand of the expression. + // + // For example, if `a / d` is on the right of operator `*`, we need to parenthesize + // to preserve the intended order of operations: `x * (a / d)` + // + // If `a ** d` is on the left of operator `**`, we need to parenthesize to preserve + // the intended order of operations: `(a ** b) ** c` + const binaryOperatorPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, binaryOperator); + const binaryOperatorAssociativity = getOperatorAssociativity(SyntaxKind.BinaryExpression, binaryOperator); + const emittedOperand = skipPartiallyEmittedExpressions(operand); + const operandPrecedence = getExpressionPrecedence(emittedOperand); + switch (compareValues(operandPrecedence, binaryOperatorPrecedence)) { + case Comparison.LessThan: + // If the operand is the right side of a right-associative binary operation + // and is a yield expression, then we do not need parentheses. + if (!isLeftSideOfBinary + && binaryOperatorAssociativity === Associativity.Right + && operand.kind === SyntaxKind.YieldExpression) { + return false; + } + + return true; + + case Comparison.GreaterThan: + return false; + + case Comparison.EqualTo: + if (isLeftSideOfBinary) { + // No need to parenthesize the left operand when the binary operator is + // left associative: + // (a*b)/x -> a*b/x + // (a**b)/x -> a**b/x + // + // Parentheses are needed for the left operand when the binary operator is + // right associative: + // (a/b)**x -> (a/b)**x + // (a**b)**x -> (a**b)**x + return binaryOperatorAssociativity === Associativity.Right; + } + else { + if (isBinaryExpression(emittedOperand) + && emittedOperand.operatorToken.kind === binaryOperator) { + // No need to parenthesize the right operand when the binary operator and + // operand are the same and one of the following: + // x*(a*b) => x*a*b + // x|(a|b) => x|a|b + // x&(a&b) => x&a&b + // x^(a^b) => x^a^b + if (operatorHasAssociativeProperty(binaryOperator)) { + return false; + } + + // No need to parenthesize the right operand when the binary operator + // is plus (+) if both the left and right operands consist solely of either + // literals of the same kind or binary plus (+) expressions for literals of + // the same kind (recursively). + // "a"+(1+2) => "a"+(1+2) + // "a"+("b"+"c") => "a"+"b"+"c" + if (binaryOperator === SyntaxKind.PlusToken) { + const leftKind = leftOperand ? getLiteralKindOfBinaryPlusOperand(leftOperand) : SyntaxKind.Unknown; + if (isLiteralKind(leftKind) && leftKind === getLiteralKindOfBinaryPlusOperand(emittedOperand)) { + return false; + } + } + } + + // No need to parenthesize the right operand when the operand is right + // associative: + // x/(a**b) -> x/a**b + // x**(a**b) -> x**a**b + // + // Parentheses are needed for the right operand when the operand is left + // associative: + // x/(a*b) -> x/(a*b) + // x**(a/b) -> x**(a/b) + const operandAssociativity = getExpressionAssociativity(emittedOperand); + return operandAssociativity === Associativity.Left; + } + } + } + + /** + * Determines whether a binary operator is mathematically associative. + * + * @param binaryOperator The binary operator. + */ + function operatorHasAssociativeProperty(binaryOperator: SyntaxKind) { + // The following operators are associative in JavaScript: + // (a*b)*c -> a*(b*c) -> a*b*c + // (a|b)|c -> a|(b|c) -> a|b|c + // (a&b)&c -> a&(b&c) -> a&b&c + // (a^b)^c -> a^(b^c) -> a^b^c + // + // While addition is associative in mathematics, JavaScript's `+` is not + // guaranteed to be associative as it is overloaded with string concatenation. + return binaryOperator === SyntaxKind.AsteriskToken + || binaryOperator === SyntaxKind.BarToken + || binaryOperator === SyntaxKind.AmpersandToken + || binaryOperator === SyntaxKind.CaretToken; + } + + interface BinaryPlusExpression extends BinaryExpression { + cachedLiteralKind: SyntaxKind; + } + + /** + * This function determines whether an expression consists of a homogeneous set of + * literal expressions or binary plus expressions that all share the same literal kind. + * It is used to determine whether the right-hand operand of a binary plus expression can be + * emitted without parentheses. + */ + function getLiteralKindOfBinaryPlusOperand(node: Expression): SyntaxKind { + node = skipPartiallyEmittedExpressions(node); + + if (isLiteralKind(node.kind)) { + return node.kind; + } + + if (node.kind === SyntaxKind.BinaryExpression && (node).operatorToken.kind === SyntaxKind.PlusToken) { + if ((node).cachedLiteralKind !== undefined) { + return (node).cachedLiteralKind; + } + + const leftKind = getLiteralKindOfBinaryPlusOperand((node).left); + const literalKind = isLiteralKind(leftKind) + && leftKind === getLiteralKindOfBinaryPlusOperand((node).right) + ? leftKind + : SyntaxKind.Unknown; + + (node).cachedLiteralKind = literalKind; + return literalKind; + } + + return SyntaxKind.Unknown; + } + + /** + * Wraps an expression in parentheses if it is needed in order to use the expression + * as the expression of a NewExpression node. + * + * @param expression The Expression node. + */ + export function parenthesizeForNew(expression: Expression): LeftHandSideExpression { + const emittedExpression = skipPartiallyEmittedExpressions(expression); + switch (emittedExpression.kind) { + case SyntaxKind.CallExpression: + return createParen(expression); + + case SyntaxKind.NewExpression: + return (emittedExpression).arguments + ? expression + : createParen(expression); + } + + return parenthesizeForAccess(expression); + } + + /** + * Wraps an expression in parentheses if it is needed in order to use the expression for + * property or element access. + * + * @param expr The expression node. + */ + export function parenthesizeForAccess(expression: Expression): LeftHandSideExpression { + // isLeftHandSideExpression is almost the correct criterion for when it is not necessary + // to parenthesize the expression before a dot. The known exceptions are: + // + // NewExpression: + // new C.x -> not the same as (new C).x + // NumericLiteral + // 1.x -> not the same as (1).x + // + const emittedExpression = skipPartiallyEmittedExpressions(expression); + if (isLeftHandSideExpression(emittedExpression) + && (emittedExpression.kind !== SyntaxKind.NewExpression || (emittedExpression).arguments) + && emittedExpression.kind !== SyntaxKind.NumericLiteral) { + return expression; + } + + return createParen(expression, /*location*/ expression); + } + + export function parenthesizePostfixOperand(operand: Expression) { + return isLeftHandSideExpression(operand) + ? operand + : createParen(operand, /*location*/ operand); + } + + export function parenthesizePrefixOperand(operand: Expression) { + return isUnaryExpression(operand) + ? operand + : createParen(operand, /*location*/ operand); + } + + function parenthesizeListElements(elements: NodeArray) { + let result: Expression[]; + for (let i = 0; i < elements.length; i++) { + const element = parenthesizeExpressionForList(elements[i]); + if (result !== undefined || element !== elements[i]) { + if (result === undefined) { + result = elements.slice(0, i); + } + + result.push(element); + } + } + + if (result !== undefined) { + return createNodeArray(result, elements, elements.hasTrailingComma); + } + + return elements; + } + + export function parenthesizeExpressionForList(expression: Expression) { + const emittedExpression = skipPartiallyEmittedExpressions(expression); + const expressionPrecedence = getExpressionPrecedence(emittedExpression); + const commaPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, SyntaxKind.CommaToken); + return expressionPrecedence > commaPrecedence + ? expression + : createParen(expression, /*location*/ expression); + } + + export function parenthesizeExpressionForExpressionStatement(expression: Expression) { + const emittedExpression = skipPartiallyEmittedExpressions(expression); + if (isCallExpression(emittedExpression)) { + const callee = emittedExpression.expression; + const kind = skipPartiallyEmittedExpressions(callee).kind; + if (kind === SyntaxKind.FunctionExpression || kind === SyntaxKind.ArrowFunction) { + const mutableCall = getMutableClone(emittedExpression); + mutableCall.expression = createParen(callee, /*location*/ callee); + return recreatePartiallyEmittedExpressions(expression, mutableCall); + } + } + else { + const leftmostExpressionKind = getLeftmostExpression(emittedExpression).kind; + if (leftmostExpressionKind === SyntaxKind.ObjectLiteralExpression || leftmostExpressionKind === SyntaxKind.FunctionExpression) { + return createParen(expression, /*location*/ expression); + } + } + + return expression; + } + + /** + * Clones a series of not-emitted expressions with a new inner expression. + * + * @param originalOuterExpression The original outer expression. + * @param newInnerExpression The new inner expression. + */ + function recreatePartiallyEmittedExpressions(originalOuterExpression: Expression, newInnerExpression: Expression) { + if (isPartiallyEmittedExpression(originalOuterExpression)) { + const clone = getMutableClone(originalOuterExpression); + clone.expression = recreatePartiallyEmittedExpressions(clone.expression, newInnerExpression); + return clone; + } + + return newInnerExpression; + } + + function getLeftmostExpression(node: Expression): Expression { + while (true) { + switch (node.kind) { + case SyntaxKind.PostfixUnaryExpression: + node = (node).operand; + continue; + + case SyntaxKind.BinaryExpression: + node = (node).left; + continue; + + case SyntaxKind.ConditionalExpression: + node = (node).condition; + continue; + + case SyntaxKind.CallExpression: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.PropertyAccessExpression: + node = (node).expression; + continue; + + case SyntaxKind.PartiallyEmittedExpression: + node = (node).expression; + continue; + } + + return node; + } + } + + export function parenthesizeConciseBody(body: ConciseBody): ConciseBody { + const emittedBody = skipPartiallyEmittedExpressions(body); + if (emittedBody.kind === SyntaxKind.ObjectLiteralExpression) { + return createParen(body, /*location*/ body); + } + + return body; + } + + export const enum OuterExpressionKinds { + Parentheses = 1 << 0, + Assertions = 1 << 1, + PartiallyEmittedExpressions = 1 << 2, + + All = Parentheses | Assertions | PartiallyEmittedExpressions + } + + export function skipOuterExpressions(node: Expression, kinds?: OuterExpressionKinds): Expression; + export function skipOuterExpressions(node: Node, kinds?: OuterExpressionKinds): Node; + export function skipOuterExpressions(node: Node, kinds = OuterExpressionKinds.All) { + let previousNode: Node; + do { + previousNode = node; + if (kinds & OuterExpressionKinds.Parentheses) { + node = skipParentheses(node); + } + + if (kinds & OuterExpressionKinds.Assertions) { + node = skipAssertions(node); + } + + if (kinds & OuterExpressionKinds.PartiallyEmittedExpressions) { + node = skipPartiallyEmittedExpressions(node); + } + } + while (previousNode !== node); + + return node; + } + + export function skipParentheses(node: Expression): Expression; + export function skipParentheses(node: Node): Node; + export function skipParentheses(node: Node): Node { + while (node.kind === SyntaxKind.ParenthesizedExpression) { + node = (node).expression; + } + + return node; + } + + export function skipAssertions(node: Expression): Expression; + export function skipAssertions(node: Node): Node; + export function skipAssertions(node: Node): Node { + while (isAssertionExpression(node)) { + node = (node).expression; + } + + return node; + } + + export function skipPartiallyEmittedExpressions(node: Expression): Expression; + export function skipPartiallyEmittedExpressions(node: Node): Node; + export function skipPartiallyEmittedExpressions(node: Node) { + while (node.kind === SyntaxKind.PartiallyEmittedExpression) { + node = (node).expression; + } + + return node; + } + export function startOnNewLine(node: T): T { node.startsOnNewLine = true; return node; @@ -3508,407 +3909,4 @@ namespace ts { Debug.assertNode(node, isExpression); return node; } - - // Parenthesizing - - /** - * Wraps the operand to a BinaryExpression in parentheses if they are needed to preserve the intended - * order of operations. - * - * @param binaryOperator The operator for the BinaryExpression. - * @param operand The operand for the BinaryExpression. - * @param isLeftSideOfBinary A value indicating whether the operand is the left side of the - * BinaryExpression. - */ - export function parenthesizeBinaryOperand(binaryOperator: SyntaxKind, operand: Expression, isLeftSideOfBinary: boolean, leftOperand?: Expression) { - const skipped = skipPartiallyEmittedExpressions(operand); - - // If the resulting expression is already parenthesized, we do not need to do any further processing. - if (skipped.kind === SyntaxKind.ParenthesizedExpression) { - return operand; - } - - return binaryOperandNeedsParentheses(binaryOperator, operand, isLeftSideOfBinary, leftOperand) - ? createParen(operand) - : operand; - } - - /** - * Determines whether the operand to a BinaryExpression needs to be parenthesized. - * - * @param binaryOperator The operator for the BinaryExpression. - * @param operand The operand for the BinaryExpression. - * @param isLeftSideOfBinary A value indicating whether the operand is the left side of the - * BinaryExpression. - */ - function binaryOperandNeedsParentheses(binaryOperator: SyntaxKind, operand: Expression, isLeftSideOfBinary: boolean, leftOperand: Expression) { - // If the operand has lower precedence, then it needs to be parenthesized to preserve the - // intent of the expression. For example, if the operand is `a + b` and the operator is - // `*`, then we need to parenthesize the operand to preserve the intended order of - // operations: `(a + b) * x`. - // - // If the operand has higher precedence, then it does not need to be parenthesized. For - // example, if the operand is `a * b` and the operator is `+`, then we do not need to - // parenthesize to preserve the intended order of operations: `a * b + x`. - // - // If the operand has the same precedence, then we need to check the associativity of - // the operator based on whether this is the left or right operand of the expression. - // - // For example, if `a / d` is on the right of operator `*`, we need to parenthesize - // to preserve the intended order of operations: `x * (a / d)` - // - // If `a ** d` is on the left of operator `**`, we need to parenthesize to preserve - // the intended order of operations: `(a ** b) ** c` - const binaryOperatorPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, binaryOperator); - const binaryOperatorAssociativity = getOperatorAssociativity(SyntaxKind.BinaryExpression, binaryOperator); - const emittedOperand = skipPartiallyEmittedExpressions(operand); - const operandPrecedence = getExpressionPrecedence(emittedOperand); - switch (compareValues(operandPrecedence, binaryOperatorPrecedence)) { - case Comparison.LessThan: - // If the operand is the right side of a right-associative binary operation - // and is a yield expression, then we do not need parentheses. - if (!isLeftSideOfBinary - && binaryOperatorAssociativity === Associativity.Right - && operand.kind === SyntaxKind.YieldExpression) { - return false; - } - - return true; - - case Comparison.GreaterThan: - return false; - - case Comparison.EqualTo: - if (isLeftSideOfBinary) { - // No need to parenthesize the left operand when the binary operator is - // left associative: - // (a*b)/x -> a*b/x - // (a**b)/x -> a**b/x - // - // Parentheses are needed for the left operand when the binary operator is - // right associative: - // (a/b)**x -> (a/b)**x - // (a**b)**x -> (a**b)**x - return binaryOperatorAssociativity === Associativity.Right; - } - else { - if (isBinaryExpression(emittedOperand) - && emittedOperand.operatorToken.kind === binaryOperator) { - // No need to parenthesize the right operand when the binary operator and - // operand are the same and one of the following: - // x*(a*b) => x*a*b - // x|(a|b) => x|a|b - // x&(a&b) => x&a&b - // x^(a^b) => x^a^b - if (operatorHasAssociativeProperty(binaryOperator)) { - return false; - } - - // No need to parenthesize the right operand when the binary operator - // is plus (+) if both the left and right operands consist solely of either - // literals of the same kind or binary plus (+) expressions for literals of - // the same kind (recursively). - // "a"+(1+2) => "a"+(1+2) - // "a"+("b"+"c") => "a"+"b"+"c" - if (binaryOperator === SyntaxKind.PlusToken) { - const leftKind = leftOperand ? getLiteralKindOfBinaryPlusOperand(leftOperand) : SyntaxKind.Unknown; - if (isLiteralKind(leftKind) && leftKind === getLiteralKindOfBinaryPlusOperand(emittedOperand)) { - return false; - } - } - } - - // No need to parenthesize the right operand when the operand is right - // associative: - // x/(a**b) -> x/a**b - // x**(a**b) -> x**a**b - // - // Parentheses are needed for the right operand when the operand is left - // associative: - // x/(a*b) -> x/(a*b) - // x**(a/b) -> x**(a/b) - const operandAssociativity = getExpressionAssociativity(emittedOperand); - return operandAssociativity === Associativity.Left; - } - } - } - - /** - * Determines whether a binary operator is mathematically associative. - * - * @param binaryOperator The binary operator. - */ - function operatorHasAssociativeProperty(binaryOperator: SyntaxKind) { - // The following operators are associative in JavaScript: - // (a*b)*c -> a*(b*c) -> a*b*c - // (a|b)|c -> a|(b|c) -> a|b|c - // (a&b)&c -> a&(b&c) -> a&b&c - // (a^b)^c -> a^(b^c) -> a^b^c - // - // While addition is associative in mathematics, JavaScript's `+` is not - // guaranteed to be associative as it is overloaded with string concatenation. - return binaryOperator === SyntaxKind.AsteriskToken - || binaryOperator === SyntaxKind.BarToken - || binaryOperator === SyntaxKind.AmpersandToken - || binaryOperator === SyntaxKind.CaretToken; - } - - interface BinaryPlusExpression extends BinaryExpression { - cachedLiteralKind: SyntaxKind; - } - - /** - * This function determines whether an expression consists of a homogeneous set of - * literal expressions or binary plus expressions that all share the same literal kind. - * It is used to determine whether the right-hand operand of a binary plus expression can be - * emitted without parentheses. - */ - function getLiteralKindOfBinaryPlusOperand(node: Expression): SyntaxKind { - node = skipPartiallyEmittedExpressions(node); - - if (isLiteralKind(node.kind)) { - return node.kind; - } - - if (node.kind === SyntaxKind.BinaryExpression && (node).operatorToken.kind === SyntaxKind.PlusToken) { - if ((node).cachedLiteralKind !== undefined) { - return (node).cachedLiteralKind; - } - - const leftKind = getLiteralKindOfBinaryPlusOperand((node).left); - const literalKind = isLiteralKind(leftKind) - && leftKind === getLiteralKindOfBinaryPlusOperand((node).right) - ? leftKind - : SyntaxKind.Unknown; - - (node).cachedLiteralKind = literalKind; - return literalKind; - } - - return SyntaxKind.Unknown; - } - - /** - * Wraps an expression in parentheses if it is needed in order to use the expression - * as the expression of a NewExpression node. - * - * @param expression The Expression node. - */ - export function parenthesizeForNew(expression: Expression): LeftHandSideExpression { - const emittedExpression = skipPartiallyEmittedExpressions(expression); - switch (emittedExpression.kind) { - case SyntaxKind.CallExpression: - return createParen(expression); - - case SyntaxKind.NewExpression: - return (emittedExpression).arguments - ? expression - : createParen(expression); - } - - return parenthesizeForAccess(expression); - } - - /** - * Wraps an expression in parentheses if it is needed in order to use the expression for - * property or element access. - * - * @param expr The expression node. - */ - export function parenthesizeForAccess(expression: Expression): LeftHandSideExpression { - // isLeftHandSideExpression is almost the correct criterion for when it is not necessary - // to parenthesize the expression before a dot. The known exceptions are: - // - // NewExpression: - // new C.x -> not the same as (new C).x - // NumericLiteral - // 1.x -> not the same as (1).x - // - const emittedExpression = skipPartiallyEmittedExpressions(expression); - if (isLeftHandSideExpression(emittedExpression) - && (emittedExpression.kind !== SyntaxKind.NewExpression || (emittedExpression).arguments) - && emittedExpression.kind !== SyntaxKind.NumericLiteral) { - return expression; - } - - return createParen(expression, /*location*/ expression); - } - - export function parenthesizePostfixOperand(operand: Expression) { - return isLeftHandSideExpression(operand) - ? operand - : createParen(operand, /*location*/ operand); - } - - export function parenthesizePrefixOperand(operand: Expression) { - return isUnaryExpression(operand) - ? operand - : createParen(operand, /*location*/ operand); - } - - function parenthesizeListElements(elements: NodeArray) { - let result: Expression[]; - for (let i = 0; i < elements.length; i++) { - const element = parenthesizeExpressionForList(elements[i]); - if (result !== undefined || element !== elements[i]) { - if (result === undefined) { - result = elements.slice(0, i); - } - - result.push(element); - } - } - - if (result !== undefined) { - return createNodeArray(result, elements, elements.hasTrailingComma); - } - - return elements; - } - - export function parenthesizeExpressionForList(expression: Expression) { - const emittedExpression = skipPartiallyEmittedExpressions(expression); - const expressionPrecedence = getExpressionPrecedence(emittedExpression); - const commaPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, SyntaxKind.CommaToken); - return expressionPrecedence > commaPrecedence - ? expression - : createParen(expression, /*location*/ expression); - } - - export function parenthesizeExpressionForExpressionStatement(expression: Expression) { - const emittedExpression = skipPartiallyEmittedExpressions(expression); - if (isCallExpression(emittedExpression)) { - const callee = emittedExpression.expression; - const kind = skipPartiallyEmittedExpressions(callee).kind; - if (kind === SyntaxKind.FunctionExpression || kind === SyntaxKind.ArrowFunction) { - const mutableCall = getMutableClone(emittedExpression); - mutableCall.expression = createParen(callee, /*location*/ callee); - return recreatePartiallyEmittedExpressions(expression, mutableCall); - } - } - else { - const leftmostExpressionKind = getLeftmostExpression(emittedExpression).kind; - if (leftmostExpressionKind === SyntaxKind.ObjectLiteralExpression || leftmostExpressionKind === SyntaxKind.FunctionExpression) { - return createParen(expression, /*location*/ expression); - } - } - - return expression; - } - - /** - * Clones a series of not-emitted expressions with a new inner expression. - * - * @param originalOuterExpression The original outer expression. - * @param newInnerExpression The new inner expression. - */ - function recreatePartiallyEmittedExpressions(originalOuterExpression: Expression, newInnerExpression: Expression) { - if (isPartiallyEmittedExpression(originalOuterExpression)) { - const clone = getMutableClone(originalOuterExpression); - clone.expression = recreatePartiallyEmittedExpressions(clone.expression, newInnerExpression); - return clone; - } - - return newInnerExpression; - } - - function getLeftmostExpression(node: Expression): Expression { - while (true) { - switch (node.kind) { - case SyntaxKind.PostfixUnaryExpression: - node = (node).operand; - continue; - - case SyntaxKind.BinaryExpression: - node = (node).left; - continue; - - case SyntaxKind.ConditionalExpression: - node = (node).condition; - continue; - - case SyntaxKind.CallExpression: - case SyntaxKind.ElementAccessExpression: - case SyntaxKind.PropertyAccessExpression: - node = (node).expression; - continue; - - case SyntaxKind.PartiallyEmittedExpression: - node = (node).expression; - continue; - } - - return node; - } - } - - export function parenthesizeConciseBody(body: ConciseBody): ConciseBody { - const emittedBody = skipPartiallyEmittedExpressions(body); - if (emittedBody.kind === SyntaxKind.ObjectLiteralExpression) { - return createParen(body, /*location*/ body); - } - - return body; - } - - export const enum OuterExpressionKinds { - Parentheses = 1 << 0, - Assertions = 1 << 1, - PartiallyEmittedExpressions = 1 << 2, - - All = Parentheses | Assertions | PartiallyEmittedExpressions - } - - export function skipOuterExpressions(node: Expression, kinds?: OuterExpressionKinds): Expression; - export function skipOuterExpressions(node: Node, kinds?: OuterExpressionKinds): Node; - export function skipOuterExpressions(node: Node, kinds = OuterExpressionKinds.All) { - let previousNode: Node; - do { - previousNode = node; - if (kinds & OuterExpressionKinds.Parentheses) { - node = skipParentheses(node); - } - - if (kinds & OuterExpressionKinds.Assertions) { - node = skipAssertions(node); - } - - if (kinds & OuterExpressionKinds.PartiallyEmittedExpressions) { - node = skipPartiallyEmittedExpressions(node); - } - } - while (previousNode !== node); - - return node; - } - - export function skipParentheses(node: Expression): Expression; - export function skipParentheses(node: Node): Node; - export function skipParentheses(node: Node): Node { - while (node.kind === SyntaxKind.ParenthesizedExpression) { - node = (node).expression; - } - - return node; - } - - export function skipAssertions(node: Expression): Expression; - export function skipAssertions(node: Node): Node; - export function skipAssertions(node: Node): Node { - while (isAssertionExpression(node)) { - node = (node).expression; - } - - return node; - } - - export function skipPartiallyEmittedExpressions(node: Expression): Expression; - export function skipPartiallyEmittedExpressions(node: Node): Node; - export function skipPartiallyEmittedExpressions(node: Node) { - while (node.kind === SyntaxKind.PartiallyEmittedExpression) { - node = (node).expression; - } - - return node; - } } From ddcd22e4de4b604ee4ef532f48e3371fb4473352 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 14 Nov 2016 18:30:42 -0800 Subject: [PATCH 06/10] Removed esnext dependency on convertForOf/transformFunctionBody in factory --- src/compiler/factory.ts | 4 +- src/compiler/transformers/destructuring.ts | 10 +- src/compiler/transformers/esnext.ts | 305 +++++++++++++-------- src/compiler/utilities.ts | 6 + 4 files changed, 204 insertions(+), 121 deletions(-) diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 919864628da..5727081dc78 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -1528,6 +1528,8 @@ namespace ts { return createBinary(left, SyntaxKind.LessThanToken, right, location); } + export function createAssignment(left: ObjectLiteralExpression | ArrayLiteralExpression, right: Expression, location?: TextRange): DestructuringAssignment; + export function createAssignment(left: Expression, right: Expression, location?: TextRange): BinaryExpression; export function createAssignment(left: Expression, right: Expression, location?: TextRange) { return createBinary(left, SyntaxKind.EqualsToken, right, location); } @@ -2345,7 +2347,7 @@ namespace ts { if (isBlock(node)) { return node; } - return createBlock([createReturn(node, node)], node); + return createBlock([createReturn(node, node)], node, /*multiLine*/ true); } function isUseStrictPrologue(node: ExpressionStatement): boolean { diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index 433305ca6b2..30484ffaf5c 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -54,7 +54,7 @@ namespace ts { } } - const expressions: Expression[] = []; + let expressions: Expression[]; const host: FlattenHost = { context, level, @@ -92,17 +92,21 @@ namespace ts { flattenBindingOrAssignmentElement(host, node, value, location, /*skipInitializer*/ isDestructuringAssignment(node)); if (value && needsValue) { + if (!some(expressions)) { + return value; + } + expressions.push(value); } - return aggregateTransformFlags(inlineExpressions(expressions)); + return aggregateTransformFlags(inlineExpressions(expressions)) || createOmittedExpression(); function emitExpression(expression: Expression) { // NOTE: this completely disables source maps, but aligns with the behavior of // `emitAssignment` in the old emitter. setEmitFlags(expression, EmitFlags.NoNestedSourceMaps); aggregateTransformFlags(expression); - expressions.push(expression); + expressions = append(expressions, expression); } function emitBindingOrAssignment(target: BindingOrAssignmentElementTarget, value: Expression, location: TextRange, original: Node) { diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index fb854318e69..85dd29d0725 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -4,6 +4,9 @@ /*@internal*/ namespace ts { export function transformESNext(context: TransformationContext) { + const { + endLexicalEnvironment + } = context; let currentSourceFile: SourceFile; return transformSourceFile; @@ -37,6 +40,14 @@ namespace ts { case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: return node; + case SyntaxKind.Constructor: + return visitConstructorDeclaration(node as ConstructorDeclaration); + case SyntaxKind.MethodDeclaration: + return visitMethodDeclaration(node as MethodDeclaration); + case SyntaxKind.GetAccessor: + return visitGetAccessorDeclaration(node as GetAccessorDeclaration); + case SyntaxKind.SetAccessor: + return visitSetAccessorDeclaration(node as SetAccessorDeclaration); case SyntaxKind.FunctionDeclaration: return visitFunctionDeclaration(node as FunctionDeclaration); case SyntaxKind.FunctionExpression: @@ -134,7 +145,7 @@ namespace ts { * @param node A BinaryExpression node. */ function visitBinaryExpression(node: BinaryExpression, needsDestructuringValue: boolean): Expression { - if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.ContainsESNext) { + if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.ContainsObjectRest) { return flattenDestructuringAssignment( context, node, @@ -144,7 +155,6 @@ namespace ts { visitor ); } - return visitEachChild(node, visitor, context); } @@ -155,8 +165,15 @@ namespace ts { */ function visitVariableDeclaration(node: VariableDeclaration): VisitResult { // If we are here it is because the name contains a binding pattern with a rest somewhere in it. - if (isBindingPattern(node.name) && node.name.transformFlags & TransformFlags.AssertESNext) { - return flattenDestructuringBinding(context, node, /*boundValue*/ undefined, /*skipInitializer*/ false, /*recordTempVariablesInLine*/ true, FlattenLevel.ObjectRest, visitor); + if (isBindingPattern(node.name) && node.name.transformFlags & TransformFlags.ContainsObjectRest) { + return flattenDestructuringBinding( + context, + node, + /*boundValue*/ undefined, + /*skipInitializer*/ false, + /*recordTempVariablesInLine*/ true, + FlattenLevel.ObjectRest, + visitor); } return visitEachChild(node, visitor, context); } @@ -167,140 +184,194 @@ namespace ts { * @param node A ForOfStatement. */ function visitForOfStatement(node: ForOfStatement): VisitResult { - // The following ESNext code: - // - // for (let { x, y, ...rest } of expr) { } - // - // should be emitted as - // - // for (var _a of expr) { - // let { x, y } = _a, rest = __rest(_a, ["x", "y"]); - // } - // - // where _a is a temp emitted to capture the RHS. - // When the left hand side is an expression instead of a let declaration, - // the `let` before the `{ x, y }` is not emitted. - // When the left hand side is a let/const, the v is renamed if there is - // another v in scope. - // Note that all assignments to the LHS are emitted in the body, including - // all destructuring. - // Note also that because an extra statement is needed to assign to the LHS, - // for-of bodies are always emitted as blocks. - - // for ( of ) - // where is [let] variabledeclarationlist | expression - const initializer = node.initializer; - if (!isRestBindingPattern(initializer) && !isRestAssignment(initializer)) { - return visitEachChild(node, visitor, context); + let leadingStatements: Statement[]; + let temp: Identifier; + const initializer = skipParentheses(node.initializer); + if (initializer.transformFlags & TransformFlags.ContainsObjectRest) { + if (isVariableDeclarationList(initializer)) { + temp = createTempVariable(/*recordTempVariable*/ undefined); + const firstDeclaration = firstOrUndefined(initializer.declarations); + const declarations = flattenDestructuringBinding( + context, + firstDeclaration, + temp, + /*skipInitializer*/ true, + /*recordTempVariablesInLine*/ true, + FlattenLevel.ObjectRest, + visitor + ); + if (some(declarations)) { + const statement = createVariableStatement( + /*modifiers*/ undefined, + updateVariableDeclarationList(initializer, declarations), + /*location*/ initializer + ); + leadingStatements = append(leadingStatements, statement); + } + } + else if (isAssignmentPattern(initializer)) { + temp = createTempVariable(/*recordTempVariable*/ undefined); + const expression = flattenDestructuringAssignment( + context, + aggregateTransformFlags(createAssignment(initializer, temp, /*location*/ node.initializer)), + /*needsValue*/ false, + FlattenLevel.ObjectRest, + /*createAssignmentCallback*/ undefined, + visitor + ); + leadingStatements = append(leadingStatements, createStatement(expression, /*location*/ node.initializer)); + } } - - return convertForOf(node, undefined, visitor, noop, context, /*transformRest*/ true); - } - - function isRestBindingPattern(initializer: ForInitializer) { - if (isVariableDeclarationList(initializer)) { - const declaration = firstOrUndefined(initializer.declarations); - return declaration && declaration.name && - declaration.name.kind === SyntaxKind.ObjectBindingPattern && - !!(declaration.name.transformFlags & TransformFlags.ContainsObjectRest); + if (temp) { + const expression = visitNode(node.expression, visitor, isExpression); + const statement = visitNode(node.statement, visitor, isStatement); + const block = isBlock(statement) + ? updateBlock(statement, createNodeArray(concatenate(leadingStatements, statement.statements), statement.statements)) + : createBlock(append(leadingStatements, statement), statement, /*multiLine*/ true); + return updateForOf( + node, + createVariableDeclarationList( + [ + createVariableDeclaration(temp, /*type*/ undefined, /*initializer*/ undefined, node.initializer) + ], + node.initializer, + NodeFlags.Let + ), + expression, + block + ); } - return false; - } - - function isRestAssignment(initializer: ForInitializer) { - return initializer.kind === SyntaxKind.ObjectLiteralExpression && - initializer.transformFlags & TransformFlags.ContainsObjectRest; + return visitEachChild(node, visitor, context); } function visitParameter(node: ParameterDeclaration): ParameterDeclaration { - if (isObjectRestParameter(node)) { + if (node.transformFlags & TransformFlags.ContainsObjectRest) { // Binding patterns are converted into a generated name and are // evaluated inside the function body. - return setOriginalNode( - createParameter( - /*decorators*/ undefined, - /*modifiers*/ undefined, - /*dotDotDotToken*/ undefined, - getGeneratedNameForNode(node), - /*questionToken*/ undefined, - /*type*/ undefined, - node.initializer, - /*location*/ node - ), - /*original*/ node + return updateParameter( + node, + /*decorators*/ undefined, + /*modifiers*/ undefined, + node.dotDotDotToken, + getGeneratedNameForNode(node), + /*type*/ undefined, + visitNode(node.initializer, visitor, isExpression) ); } - else { - return node; - } + return visitEachChild(node, visitor, context); } - function isObjectRestParameter(node: ParameterDeclaration) { - return node.name && - node.name.kind === SyntaxKind.ObjectBindingPattern && - !!(node.name.transformFlags & TransformFlags.ContainsObjectRest); + function visitConstructorDeclaration(node: ConstructorDeclaration) { + return updateConstructor( + node, + /*decorators*/ undefined, + node.modifiers, + visitParameterList(node.parameters, visitor, context), + transformFunctionBody(node) + ); } - function visitFunctionDeclaration(node: FunctionDeclaration): FunctionDeclaration { - const hasRest = forEach(node.parameters, isObjectRestParameter); - const body = hasRest ? - transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block : - visitEachChild(node.body, visitor, context); + function visitGetAccessorDeclaration(node: GetAccessorDeclaration) { + return updateGetAccessor( + node, + /*decorators*/ undefined, + node.modifiers, + visitNode(node.name, visitor, isPropertyName), + visitParameterList(node.parameters, visitor, context), + /*type*/ undefined, + transformFunctionBody(node) + ); + } - return setOriginalNode( - createFunctionDeclaration( - /*decorators*/ undefined, - node.modifiers, - node.asteriskToken, - node.name, - /*typeParameters*/ undefined, - visitNodes(node.parameters, visitor, isParameter), - /*type*/ undefined, - body, - /*location*/ node - ), - /*original*/ node); + function visitSetAccessorDeclaration(node: SetAccessorDeclaration) { + return updateSetAccessor( + node, + /*decorators*/ undefined, + node.modifiers, + visitNode(node.name, visitor, isPropertyName), + visitParameterList(node.parameters, visitor, context), + transformFunctionBody(node) + ); + } + + function visitMethodDeclaration(node: MethodDeclaration) { + return updateMethod( + node, + /*decorators*/ undefined, + node.modifiers, + visitNode(node.name, visitor, isPropertyName), + /*typeParameters*/ undefined, + visitParameterList(node.parameters, visitor, context), + /*type*/ undefined, + transformFunctionBody(node) + ); + } + + function visitFunctionDeclaration(node: FunctionDeclaration) { + return updateFunctionDeclaration( + node, + /*decorators*/ undefined, + node.modifiers, + node.name, + /*typeParameters*/ undefined, + visitParameterList(node.parameters, visitor, context), + /*type*/ undefined, + transformFunctionBody(node) + ); } function visitArrowFunction(node: ArrowFunction) { - const hasRest = forEach(node.parameters, isObjectRestParameter); - const body = hasRest ? - transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block : - visitEachChild(node.body, visitor, context); - const func = setOriginalNode( - createArrowFunction( - /*modifiers*/ undefined, - /*typeParameters*/ undefined, - visitNodes(node.parameters, visitor, isParameter), - /*type*/ undefined, - node.equalsGreaterThanToken, - body, - /*location*/ node - ), - /*original*/ node + return updateArrowFunction( + node, + node.modifiers, + /*typeParameters*/ undefined, + visitParameterList(node.parameters, visitor, context), + /*type*/ undefined, + transformFunctionBody(node) ); - setEmitFlags(func, EmitFlags.CapturesThis); - return func; } - function visitFunctionExpression(node: FunctionExpression): Expression { - const hasRest = forEach(node.parameters, isObjectRestParameter); - const body = hasRest ? - transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block : - visitEachChild(node.body, visitor, context); - return setOriginalNode( - createFunctionExpression( - /*modifiers*/ undefined, - node.asteriskToken, - name, - /*typeParameters*/ undefined, - visitNodes(node.parameters, visitor, isParameter), - /*type*/ undefined, - body, - /*location*/ node - ), - /*original*/ node + function visitFunctionExpression(node: FunctionExpression) { + return updateFunctionExpression( + node, + node.modifiers, + node.name, + /*typeParameters*/ undefined, + visitParameterList(node.parameters, visitor, context), + /*type*/ undefined, + transformFunctionBody(node) ); } + + function transformFunctionBody(node: FunctionDeclaration | FunctionExpression | ConstructorDeclaration | MethodDeclaration | AccessorDeclaration): FunctionBody; + function transformFunctionBody(node: ArrowFunction): ConciseBody; + function transformFunctionBody(node: FunctionLikeDeclaration): ConciseBody { + let leadingStatements: Statement[]; + for (const parameter of node.parameters) { + if (parameter.transformFlags & TransformFlags.ContainsObjectRest) { + const temp = getGeneratedNameForNode(parameter); + const declarations = flattenDestructuringBinding(context, parameter, temp, /*skipInitializer*/ true, /*recordTempVariablesInLine*/ true, FlattenLevel.ObjectRest, visitor); + if (some(declarations)) { + const statement = createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList( + declarations + ) + ); + setEmitFlags(statement, EmitFlags.CustomPrologue); + leadingStatements = append(leadingStatements, statement); + } + } + } + + const body = visitNode(node.body, visitor, isConciseBody); + const trailingStatements = endLexicalEnvironment(); + if (some(leadingStatements) || some(trailingStatements)) { + const block = convertToFunctionBody(body); + return updateBlock(block, createNodeArray(concatenate(concatenate(leadingStatements, block.statements), trailingStatements), block.statements)); + } + + return body; + } } } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 317cad49def..dd2afc38cbf 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3950,6 +3950,12 @@ namespace ts { return false; } + export function isAssignmentPattern(node: Node): node is AssignmentPattern { + const kind = node.kind; + return kind === SyntaxKind.ArrayLiteralExpression + || kind === SyntaxKind.ObjectLiteralExpression; + } + export function isBindingElement(node: Node): node is BindingElement { return node.kind === SyntaxKind.BindingElement; } From dff9849ac935c13f7cb184192ec40151a916c7f0 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 14 Nov 2016 18:33:21 -0800 Subject: [PATCH 07/10] Make multiLine optional in convertToFunctionBody --- src/compiler/factory.ts | 4 ++-- src/compiler/transformers/esnext.ts | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 5727081dc78..9c23cfd9b97 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -2343,11 +2343,11 @@ namespace ts { return qualifiedName; } - export function convertToFunctionBody(node: ConciseBody) { + export function convertToFunctionBody(node: ConciseBody, multiLine?: boolean) { if (isBlock(node)) { return node; } - return createBlock([createReturn(node, node)], node, /*multiLine*/ true); + return createBlock([createReturn(node, node)], node, multiLine); } function isUseStrictPrologue(node: ExpressionStatement): boolean { diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 85dd29d0725..2a7fb855a92 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -363,14 +363,12 @@ namespace ts { } } } - const body = visitNode(node.body, visitor, isConciseBody); const trailingStatements = endLexicalEnvironment(); if (some(leadingStatements) || some(trailingStatements)) { - const block = convertToFunctionBody(body); + const block = convertToFunctionBody(body, /*multiLine*/ true); return updateBlock(block, createNodeArray(concatenate(concatenate(leadingStatements, block.statements), trailingStatements), block.statements)); } - return body; } } From b4d3bca32b59dbb4005f89154ba2a9654658a735 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 15 Nov 2016 09:50:29 -0800 Subject: [PATCH 08/10] Object rest emit for method and accessor parameters I missed these before, so emit was incorrect for object rest in a method or accessor parameter. --- src/compiler/binder.ts | 10 ++++ src/compiler/transformers/esnext.ts | 75 +++++++++++++++++++++++------ 2 files changed, 69 insertions(+), 16 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 961ca205281..6b480699a55 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2771,6 +2771,11 @@ namespace ts { transformFlags |= TransformFlags.AssertTypeScript; } + // a method declaration with object rest destructuring is ES Next syntax + if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { + transformFlags |= TransformFlags.AssertESNext; + } + // An async method declaration is ES2017 syntax. if (hasModifier(node, ModifierFlags.Async)) { transformFlags |= TransformFlags.AssertES2017; @@ -2797,6 +2802,11 @@ namespace ts { transformFlags |= TransformFlags.AssertTypeScript; } + // a method declaration with object rest destructuring is ES Next syntax + if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { + transformFlags |= TransformFlags.AssertESNext; + } + node.transformFlags = transformFlags | TransformFlags.HasComputedFlags; return transformFlags & ~TransformFlags.MethodOrAccessorExcludes; } diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 1fad209bdb3..0db09d79570 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -46,6 +46,11 @@ namespace ts { return visitFunctionExpression(node as FunctionExpression); case SyntaxKind.ArrowFunction: return visitArrowFunction(node as ArrowFunction); + case SyntaxKind.MethodDeclaration: + return visitMethodDeclaration(node as MethodDeclaration); + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return visitAccessorDeclaration(node as AccessorDeclaration); case SyntaxKind.Parameter: return visitParameter(node as ParameterDeclaration); default: @@ -208,11 +213,6 @@ namespace ts { } function visitFunctionDeclaration(node: FunctionDeclaration): FunctionDeclaration { - const hasRest = forEach(node.parameters, isObjectRestParameter); - const body = hasRest ? - transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block : - visitEachChild(node.body, visitor, context); - return setOriginalNode( createFunctionDeclaration( /*decorators*/ undefined, @@ -222,17 +222,13 @@ namespace ts { /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, - body, + transformFunctionBodyIfNeeded(node), /*location*/ node ), /*original*/ node); } function visitArrowFunction(node: ArrowFunction) { - const hasRest = forEach(node.parameters, isObjectRestParameter); - const body = hasRest ? - transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block : - visitEachChild(node.body, visitor, context); const func = setOriginalNode( createArrowFunction( /*modifiers*/ undefined, @@ -240,7 +236,7 @@ namespace ts { visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, node.equalsGreaterThanToken, - body, + transformFunctionBodyIfNeeded(node), /*location*/ node ), /*original*/ node @@ -250,10 +246,6 @@ namespace ts { } function visitFunctionExpression(node: FunctionExpression): Expression { - const hasRest = forEach(node.parameters, isObjectRestParameter); - const body = hasRest ? - transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block : - visitEachChild(node.body, visitor, context); return setOriginalNode( createFunctionExpression( /*modifiers*/ undefined, @@ -262,11 +254,62 @@ namespace ts { /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, - body, + transformFunctionBodyIfNeeded(node), /*location*/ node ), /*original*/ node ); } + + function visitMethodDeclaration(node: MethodDeclaration): MethodDeclaration { + return setOriginalNode( + createMethod( + /*decorators*/ undefined, + node.modifiers, + node.asteriskToken, + node.name, + /*typeParameters*/ undefined, + visitNodes(node.parameters, visitor, isParameter), + /*type*/ undefined, + transformFunctionBodyIfNeeded(node), + /*location*/ node + ), + /*original*/ node); + } + + function visitAccessorDeclaration(node: AccessorDeclaration): AccessorDeclaration { + if (node.kind === SyntaxKind.GetAccessor) { + return setOriginalNode( + createGetAccessor( + /*decorators*/ undefined, + node.modifiers, + node.name, + visitNodes(node.parameters, visitor, isParameter), + /*type*/ undefined, + transformFunctionBodyIfNeeded(node), + /*location*/ node + ), + /*original*/ node); + } + else { + return setOriginalNode( + createSetAccessor( + /*decorators*/ undefined, + node.modifiers, + node.name, + visitNodes(node.parameters, visitor, isParameter), + transformFunctionBodyIfNeeded(node), + /*location*/ node + ), + /*original*/ node); + } + } + + function transformFunctionBodyIfNeeded(node: FunctionLikeDeclaration): Block { + const hasRest = forEach(node.parameters, isObjectRestParameter); + return hasRest ? + transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) : + visitEachChild(node.body, visitor, context) as Block; + } } } From 498d978c216701e25046da7b3e5eda13f55f4a6f Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 15 Nov 2016 09:55:56 -0800 Subject: [PATCH 09/10] Test object rest parameter emit: methods/accessors --- .../reference/objectRestParameter.js | 19 +++++++++++++++ .../reference/objectRestParameter.symbols | 23 +++++++++++++++++++ .../reference/objectRestParameter.types | 23 +++++++++++++++++++ .../types/rest/objectRestParameter.ts | 9 ++++++++ 4 files changed, 74 insertions(+) diff --git a/tests/baselines/reference/objectRestParameter.js b/tests/baselines/reference/objectRestParameter.js index 49434f24eec..a05448a8be2 100644 --- a/tests/baselines/reference/objectRestParameter.js +++ b/tests/baselines/reference/objectRestParameter.js @@ -6,6 +6,15 @@ declare function suddenly(f: (a: { x: { z, ka }, y: string }) => void); suddenly(({ x: a, ...rest }) => rest.y); suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka); +class C { + m({ a, ...clone }: { a: number, b: string}): void { + // actually, never mind, don't clone + } + set p({ a, ...clone }: { a: number, b: string}) { + // actually, never mind, don't clone + } +} + //// [objectRestParameter.js] @@ -26,3 +35,13 @@ suddenly((_a = { x: { z: 1, ka: 1 }, y: 'noo' }) => { var _b = _a.x, { z = 12 } = _b, nested = __rest(_b, ["z"]), rest = __rest(_a, ["x"]); return rest.y + nested.ka; }); +class C { + m(_a) { + var { a } = _a, clone = __rest(_a, ["a"]); + // actually, never mind, don't clone + } + set p(_a) { + var { a } = _a, clone = __rest(_a, ["a"]); + // actually, never mind, don't clone + } +} diff --git a/tests/baselines/reference/objectRestParameter.symbols b/tests/baselines/reference/objectRestParameter.symbols index 9569dc53d3a..c43a8ba5a04 100644 --- a/tests/baselines/reference/objectRestParameter.symbols +++ b/tests/baselines/reference/objectRestParameter.symbols @@ -42,4 +42,27 @@ suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' >nested : Symbol(nested, Decl(objectRestParameter.ts, 5, 24)) >ka : Symbol(ka, Decl(objectRestParameter.ts, 3, 42)) +class C { +>C : Symbol(C, Decl(objectRestParameter.ts, 5, 107)) + + m({ a, ...clone }: { a: number, b: string}): void { +>m : Symbol(C.m, Decl(objectRestParameter.ts, 7, 9)) +>a : Symbol(a, Decl(objectRestParameter.ts, 8, 7)) +>clone : Symbol(clone, Decl(objectRestParameter.ts, 8, 10)) +>a : Symbol(a, Decl(objectRestParameter.ts, 8, 24)) +>b : Symbol(b, Decl(objectRestParameter.ts, 8, 35)) + + // actually, never mind, don't clone + } + set p({ a, ...clone }: { a: number, b: string}) { +>p : Symbol(C.p, Decl(objectRestParameter.ts, 10, 5)) +>a : Symbol(a, Decl(objectRestParameter.ts, 11, 11)) +>clone : Symbol(clone, Decl(objectRestParameter.ts, 11, 14)) +>a : Symbol(a, Decl(objectRestParameter.ts, 11, 28)) +>b : Symbol(b, Decl(objectRestParameter.ts, 11, 39)) + + // actually, never mind, don't clone + } +} + diff --git a/tests/baselines/reference/objectRestParameter.types b/tests/baselines/reference/objectRestParameter.types index c634c9c5cd5..56e7352870f 100644 --- a/tests/baselines/reference/objectRestParameter.types +++ b/tests/baselines/reference/objectRestParameter.types @@ -53,4 +53,27 @@ suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' >nested : { ka: any; } >ka : any +class C { +>C : C + + m({ a, ...clone }: { a: number, b: string}): void { +>m : ({a, ...clone}: { a: number; b: string; }) => void +>a : number +>clone : { b: string; } +>a : number +>b : string + + // actually, never mind, don't clone + } + set p({ a, ...clone }: { a: number, b: string}) { +>p : { a: number; b: string; } +>a : number +>clone : { b: string; } +>a : number +>b : string + + // actually, never mind, don't clone + } +} + diff --git a/tests/cases/conformance/types/rest/objectRestParameter.ts b/tests/cases/conformance/types/rest/objectRestParameter.ts index 5b47442f047..a9c17a29d14 100644 --- a/tests/cases/conformance/types/rest/objectRestParameter.ts +++ b/tests/cases/conformance/types/rest/objectRestParameter.ts @@ -6,3 +6,12 @@ declare function suddenly(f: (a: { x: { z, ka }, y: string }) => void); suddenly(({ x: a, ...rest }) => rest.y); suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka); +class C { + m({ a, ...clone }: { a: number, b: string}): void { + // actually, never mind, don't clone + } + set p({ a, ...clone }: { a: number, b: string}) { + // actually, never mind, don't clone + } +} + From 98e192f3571c87936524c9c1865b33916dad6eb0 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 15 Nov 2016 12:32:43 -0800 Subject: [PATCH 10/10] Move transformFunctionBody back into es2015 --- src/compiler/factory.ts | 561 +------ src/compiler/transformers/es2015.ts | 518 +++++- src/compiler/transformers/es2016.ts | 113 +- src/compiler/transformers/esnext.ts | 110 +- src/compiler/types.ts | 56 +- tests/baselines/reference/objectRestForOf.js | 8 +- ...ngForObjectBindingPatternDefaultValues2.js | 27 +- ...rObjectBindingPatternDefaultValues2.js.map | 2 +- ...BindingPatternDefaultValues2.sourcemap.txt | 1485 ++++++++--------- 9 files changed, 1405 insertions(+), 1475 deletions(-) diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 9c23cfd9b97..44db12f7b6c 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -648,7 +648,7 @@ namespace ts { export function createConditional(condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression, location?: TextRange) { const node = createNode(SyntaxKind.ConditionalExpression, location); - node.condition = condition; + node.condition = parenthesizeForConditionalHead(condition); node.questionToken = questionToken; node.whenTrue = whenTrue; node.colonToken = colonToken; @@ -2603,6 +2603,16 @@ namespace ts { return SyntaxKind.Unknown; } + export function parenthesizeForConditionalHead(condition: Expression) { + const conditionalPrecedence = getOperatorPrecedence(SyntaxKind.ConditionalExpression, SyntaxKind.QuestionToken); + const emittedCondition = skipPartiallyEmittedExpressions(condition); + const conditionPrecedence = getExpressionPrecedence(emittedCondition); + if (compareValues(conditionPrecedence, conditionalPrecedence) === Comparison.LessThan) { + return createParen(condition); + } + return condition; + } + /** * Wraps an expression in parentheses if it is needed in order to use the expression * as the expression of a NewExpression node. @@ -3102,555 +3112,6 @@ namespace ts { return tryGetModuleNameFromFile(resolver.getExternalModuleFileFromDeclaration(declaration), host, compilerOptions); } - /** - * Transforms the body of a function-like node. - * - * @param node A function-like node. - */ - export function transformFunctionBody(node: FunctionLikeDeclaration, - visitor: (node: Node) => VisitResult, - currentSourceFile: SourceFile, - context: TransformationContext, - enableSubstitutionsForCapturedThis: () => void, - convertObjectRest?: boolean) { - let multiLine = false; // indicates whether the block *must* be emitted as multiple lines - let singleLine = false; // indicates whether the block *may* be emitted as a single line - let statementsLocation: TextRange; - let closeBraceLocation: TextRange; - - const statements: Statement[] = []; - const body = node.body; - let statementOffset: number; - - context.startLexicalEnvironment(); - if (isBlock(body)) { - // ensureUseStrict is false because no new prologue-directive should be added. - // addPrologueDirectives will simply put already-existing directives at the beginning of the target statement-array - statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor); - } - - addCaptureThisForNodeIfNeeded(statements, node, enableSubstitutionsForCapturedThis); - addDefaultValueAssignmentsIfNeeded(context, statements, node, visitor, convertObjectRest); - addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false); - - // If we added any generated statements, this must be a multi-line block. - if (!multiLine && statements.length > 0) { - multiLine = true; - } - - if (isBlock(body)) { - statementsLocation = body.statements; - addRange(statements, visitNodes(body.statements, visitor, isStatement, statementOffset)); - - // If the original body was a multi-line block, this must be a multi-line block. - if (!multiLine && body.multiLine) { - multiLine = true; - } - } - else { - Debug.assert(node.kind === SyntaxKind.ArrowFunction); - - // To align with the old emitter, we use a synthetic end position on the location - // for the statement list we synthesize when we down-level an arrow function with - // an expression function body. This prevents both comments and source maps from - // being emitted for the end position only. - statementsLocation = moveRangeEnd(body, -1); - - const equalsGreaterThanToken = (node).equalsGreaterThanToken; - if (!nodeIsSynthesized(equalsGreaterThanToken) && !nodeIsSynthesized(body)) { - if (rangeEndIsOnSameLineAsRangeStart(equalsGreaterThanToken, body, currentSourceFile)) { - singleLine = true; - } - else { - multiLine = true; - } - } - - const expression = visitNode(body, visitor, isExpression); - const returnStatement = createReturn(expression, /*location*/ body); - setEmitFlags(returnStatement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTrailingComments); - statements.push(returnStatement); - - // To align with the source map emit for the old emitter, we set a custom - // source map location for the close brace. - closeBraceLocation = body; - } - - const lexicalEnvironment = context.endLexicalEnvironment(); - addRange(statements, lexicalEnvironment); - - // If we added any final generated statements, this must be a multi-line block - if (!multiLine && lexicalEnvironment && lexicalEnvironment.length) { - multiLine = true; - } - - const block = createBlock(createNodeArray(statements, statementsLocation), node.body, multiLine); - if (!multiLine && singleLine) { - setEmitFlags(block, EmitFlags.SingleLine); - } - - if (closeBraceLocation) { - setTokenSourceMapRange(block, SyntaxKind.CloseBraceToken, closeBraceLocation); - } - - setOriginalNode(block, node.body); - return block; - } - - /** - * Adds a statement to capture the `this` of a function declaration if it is needed. - * - * @param statements The statements for the new function body. - * @param node A node. - */ - export function addCaptureThisForNodeIfNeeded(statements: Statement[], node: Node, enableSubstitutionsForCapturedThis: () => void): void { - if (node.transformFlags & TransformFlags.ContainsCapturedLexicalThis && node.kind !== SyntaxKind.ArrowFunction) { - captureThisForNode(statements, node, createThis(), enableSubstitutionsForCapturedThis); - } - } - - export function captureThisForNode(statements: Statement[], node: Node, initializer: Expression | undefined, enableSubstitutionsForCapturedThis?: () => void, originalStatement?: Statement): void { - enableSubstitutionsForCapturedThis(); - const captureThisStatement = createVariableStatement( - /*modifiers*/ undefined, - createVariableDeclarationList([ - createVariableDeclaration( - "_this", - /*type*/ undefined, - initializer - ) - ]), - originalStatement - ); - - setEmitFlags(captureThisStatement, EmitFlags.NoComments | EmitFlags.CustomPrologue); - setSourceMapRange(captureThisStatement, node); - statements.push(captureThisStatement); - } - - /** - * Gets a value indicating whether we need to add default value assignments for a - * function-like node. - * - * @param node A function-like node. - */ - function shouldAddDefaultValueAssignments(node: FunctionLikeDeclaration): boolean { - return (node.transformFlags & TransformFlags.ContainsDefaultValueAssignments) !== 0; - } - - /** - * Adds statements to the body of a function-like node if it contains parameters with - * binding patterns or initializers. - * - * @param statements The statements for the new function body. - * @param node A function-like node. - */ - export function addDefaultValueAssignmentsIfNeeded(context: TransformationContext, - statements: Statement[], - node: FunctionLikeDeclaration, - visitor: (node: Node) => VisitResult, - convertObjectRest: boolean): void { - if (!shouldAddDefaultValueAssignments(node)) { - return; - } - - for (const parameter of node.parameters) { - const { name, initializer, dotDotDotToken } = parameter; - - // A rest parameter cannot have a binding pattern or an initializer, - // so let's just ignore it. - if (dotDotDotToken) { - continue; - } - - if (isBindingPattern(name)) { - addDefaultValueAssignmentForBindingPattern(context, statements, parameter, name, initializer, visitor, convertObjectRest); - } - else if (initializer) { - addDefaultValueAssignmentForInitializer(statements, parameter, name, initializer, visitor); - } - } - } - - /** - * Adds statements to the body of a function-like node for parameters with binding patterns - * - * @param statements The statements for the new function body. - * @param parameter The parameter for the function. - * @param name The name of the parameter. - * @param initializer The initializer for the parameter. - */ - function addDefaultValueAssignmentForBindingPattern(context: TransformationContext, - statements: Statement[], - parameter: ParameterDeclaration, - name: BindingPattern, initializer: Expression, - visitor: (node: Node) => VisitResult, - convertObjectRest: boolean): void { - const temp = getGeneratedNameForNode(parameter); - - // In cases where a binding pattern is simply '[]' or '{}', - // we usually don't want to emit a var declaration; however, in the presence - // of an initializer, we must emit that expression to preserve side effects. - if (name.elements.length > 0) { - statements.push( - setEmitFlags( - createVariableStatement( - /*modifiers*/ undefined, - createVariableDeclarationList( - flattenDestructuringBinding( - context, - parameter, - temp, - /*skipInitializer*/ convertObjectRest, - /*recordTempVariablesInLine*/ true, - convertObjectRest - ? FlattenLevel.ObjectRest - : FlattenLevel.All, - visitor - ) - ) - ), - EmitFlags.CustomPrologue - ) - ); - } - else if (initializer) { - statements.push( - setEmitFlags( - createStatement( - createAssignment( - temp, - visitNode(initializer, visitor, isExpression) - ) - ), - EmitFlags.CustomPrologue - ) - ); - } - } - - /** - * Adds statements to the body of a function-like node for parameters with initializers. - * - * @param statements The statements for the new function body. - * @param parameter The parameter for the function. - * @param name The name of the parameter. - * @param initializer The initializer for the parameter. - */ - function addDefaultValueAssignmentForInitializer(statements: Statement[], - parameter: ParameterDeclaration, - name: Identifier, - initializer: Expression, - visitor: (node: Node) => VisitResult): void { - initializer = visitNode(initializer, visitor, isExpression); - const statement = createIf( - createStrictEquality( - getSynthesizedClone(name), - createVoidZero() - ), - setEmitFlags( - createBlock([ - createStatement( - createAssignment( - setEmitFlags(getMutableClone(name), EmitFlags.NoSourceMap), - setEmitFlags(initializer, EmitFlags.NoSourceMap | getEmitFlags(initializer)), - /*location*/ parameter - ) - ) - ], /*location*/ parameter), - EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps - ), - /*elseStatement*/ undefined, - /*location*/ parameter - ); - statement.startsOnNewLine = true; - setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue); - statements.push(statement); - } - - /** - * Gets a value indicating whether we need to add statements to handle a rest parameter. - * - * @param node A ParameterDeclaration node. - * @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is - * part of a constructor declaration with a - * synthesized call to `super` - */ - function shouldAddRestParameter(node: ParameterDeclaration, inConstructorWithSynthesizedSuper: boolean) { - return node && node.dotDotDotToken && node.name.kind === SyntaxKind.Identifier && !inConstructorWithSynthesizedSuper; - } - - /** - * Adds statements to the body of a function-like node if it contains a rest parameter. - * - * @param statements The statements for the new function body. - * @param node A function-like node. - * @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is - * part of a constructor declaration with a - * synthesized call to `super` - */ - export function addRestParameterIfNeeded(statements: Statement[], node: FunctionLikeDeclaration, inConstructorWithSynthesizedSuper: boolean): void { - const parameter = lastOrUndefined(node.parameters); - if (!shouldAddRestParameter(parameter, inConstructorWithSynthesizedSuper)) { - return; - } - - // `declarationName` is the name of the local declaration for the parameter. - const declarationName = getMutableClone(parameter.name); - setEmitFlags(declarationName, EmitFlags.NoSourceMap); - - // `expressionName` is the name of the parameter used in expressions. - const expressionName = getSynthesizedClone(parameter.name); - const restIndex = node.parameters.length - 1; - const temp = createLoopVariable(); - - // var param = []; - statements.push( - setEmitFlags( - createVariableStatement( - /*modifiers*/ undefined, - createVariableDeclarationList([ - createVariableDeclaration( - declarationName, - /*type*/ undefined, - createArrayLiteral([]) - ) - ]), - /*location*/ parameter - ), - EmitFlags.CustomPrologue - ) - ); - - // for (var _i = restIndex; _i < arguments.length; _i++) { - // param[_i - restIndex] = arguments[_i]; - // } - const forStatement = createFor( - createVariableDeclarationList([ - createVariableDeclaration(temp, /*type*/ undefined, createLiteral(restIndex)) - ], /*location*/ parameter), - createLessThan( - temp, - createPropertyAccess(createIdentifier("arguments"), "length"), - /*location*/ parameter - ), - createPostfixIncrement(temp, /*location*/ parameter), - createBlock([ - startOnNewLine( - createStatement( - createAssignment( - createElementAccess( - expressionName, - createSubtract(temp, createLiteral(restIndex)) - ), - createElementAccess(createIdentifier("arguments"), temp) - ), - /*location*/ parameter - ) - ) - ]) - ); - - setEmitFlags(forStatement, EmitFlags.CustomPrologue); - startOnNewLine(forStatement); - statements.push(forStatement); - } - - export function convertForOf(node: ForOfStatement, convertedLoopBodyStatements: Statement[], - visitor: (node: Node) => VisitResult, - enableSubstitutionsForBlockScopedBindings: () => void, - context: TransformationContext, - convertObjectRest?: boolean): ForStatement | ForOfStatement { - // The following ES6 code: - // - // for (let v of expr) { } - // - // should be emitted as - // - // for (var _i = 0, _a = expr; _i < _a.length; _i++) { - // var v = _a[_i]; - // } - // - // where _a and _i are temps emitted to capture the RHS and the counter, - // respectively. - // When the left hand side is an expression instead of a let declaration, - // the "let v" is not emitted. - // When the left hand side is a let/const, the v is renamed if there is - // another v in scope. - // Note that all assignments to the LHS are emitted in the body, including - // all destructuring. - // Note also that because an extra statement is needed to assign to the LHS, - // for-of bodies are always emitted as blocks. - - const expression = visitNode(node.expression, visitor, isExpression); - const initializer = node.initializer; - const statements: Statement[] = []; - - // In the case where the user wrote an identifier as the RHS, like this: - // - // for (let v of arr) { } - // - // we don't want to emit a temporary variable for the RHS, just use it directly. - const counter = convertObjectRest ? undefined : createLoopVariable(); - const rhsReference = expression.kind === SyntaxKind.Identifier - ? createUniqueName((expression).text) - : createTempVariable(/*recordTempVariable*/ undefined); - const elementAccess = convertObjectRest ? rhsReference : createElementAccess(rhsReference, counter); - - // Initialize LHS - // var v = _a[_i]; - if (isVariableDeclarationList(initializer)) { - if (initializer.flags & NodeFlags.BlockScoped) { - enableSubstitutionsForBlockScopedBindings(); - } - - const firstOriginalDeclaration = firstOrUndefined(initializer.declarations); - if (firstOriginalDeclaration && isBindingPattern(firstOriginalDeclaration.name)) { - // This works whether the declaration is a var, let, or const. - // It will use rhsIterationValue _a[_i] as the initializer. - const declarations = flattenDestructuringBinding( - context, - firstOriginalDeclaration, - elementAccess, - /*skipInitializer*/ false, - /*recordTempVariablesInLine*/ true, - convertObjectRest - ? FlattenLevel.ObjectRest - : FlattenLevel.All, - visitor - ); - - const declarationList = createVariableDeclarationList(declarations, /*location*/ initializer); - setOriginalNode(declarationList, initializer); - - // Adjust the source map range for the first declaration to align with the old - // emitter. - const firstDeclaration = declarations[0]; - const lastDeclaration = lastOrUndefined(declarations); - setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end)); - - statements.push( - createVariableStatement( - /*modifiers*/ undefined, - declarationList - ) - ); - } - else { - // The following call does not include the initializer, so we have - // to emit it separately. - statements.push( - createVariableStatement( - /*modifiers*/ undefined, - setOriginalNode( - createVariableDeclarationList([ - createVariableDeclaration( - firstOriginalDeclaration ? firstOriginalDeclaration.name : createTempVariable(/*recordTempVariable*/ undefined), - /*type*/ undefined, - createElementAccess(rhsReference, counter) - ) - ], /*location*/ moveRangePos(initializer, -1)), - initializer - ), - /*location*/ moveRangeEnd(initializer, -1) - ) - ); - } - } - else { - // Initializer is an expression. Emit the expression in the body, so that it's - // evaluated on every iteration. - const assignment = createAssignment(initializer, elementAccess); - if (isDestructuringAssignment(assignment)) { - // This is a destructuring pattern, so we flatten the destructuring instead. - statements.push( - createStatement( - flattenDestructuringAssignment( - context, - assignment, - /*needsValue*/ false, - convertObjectRest - ? FlattenLevel.ObjectRest - : FlattenLevel.All, - /*createAssignmentCallback*/ undefined, - visitor - ) - ) - ); - } - else { - // Currently there is not way to check that assignment is binary expression of destructing assignment - // so we have to cast never type to binaryExpression - (assignment).end = initializer.end; - statements.push(createStatement(assignment, /*location*/ moveRangeEnd(initializer, -1))); - } - } - - let bodyLocation: TextRange; - let statementsLocation: TextRange; - if (convertedLoopBodyStatements) { - addRange(statements, convertedLoopBodyStatements); - } - else { - const statement = visitNode(node.statement, visitor, isStatement); - if (isBlock(statement)) { - addRange(statements, statement.statements); - bodyLocation = statement; - statementsLocation = statement.statements; - } - else { - statements.push(statement); - } - } - - // The old emitter does not emit source maps for the expression - setEmitFlags(expression, EmitFlags.NoSourceMap | getEmitFlags(expression)); - - // The old emitter does not emit source maps for the block. - // We add the location to preserve comments. - const body = createBlock( - createNodeArray(statements, /*location*/ statementsLocation), - /*location*/ bodyLocation - ); - - setEmitFlags(body, EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps); - - let forStatement: ForStatement | ForOfStatement; - if (convertObjectRest) { - forStatement = createForOf( - createVariableDeclarationList([ - createVariableDeclaration(rhsReference, /*type*/ undefined, /*initializer*/ undefined, /*location*/ node.expression) - ], /*location*/ node.expression), - node.expression, - body, - /*location*/ node - ); - } - else { - forStatement = createFor( - setEmitFlags( - createVariableDeclarationList([ - createVariableDeclaration(counter, /*type*/ undefined, createLiteral(0), /*location*/ moveRangePos(node.expression, -1)), - createVariableDeclaration(rhsReference, /*type*/ undefined, expression, /*location*/ node.expression) - ], /*location*/ node.expression), - EmitFlags.NoHoisting - ), - createLessThan( - counter, - createPropertyAccess(rhsReference, "length"), - /*location*/ node.expression - ), - createPostfixIncrement(counter, /*location*/ node.expression), - body, - /*location*/ node - ); - } - - // Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter. - setEmitFlags(forStatement, EmitFlags.NoTokenTrailingSourceMaps); - return forStatement; - } - /** * Gets the initializer of an BindingOrAssignmentElement. */ diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 29107e149f4..0085fcef1bc 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -861,7 +861,7 @@ namespace ts { } if (constructor) { - addDefaultValueAssignmentsIfNeeded(context, statements, constructor, visitor, /*convertObjectRest*/ false); + addDefaultValueAssignmentsIfNeeded(statements, constructor); addRestParameterIfNeeded(statements, constructor, hasSynthesizedSuper); Debug.assert(statementOffset >= 0, "statementOffset not initialized correctly!"); @@ -954,7 +954,7 @@ namespace ts { // If this isn't a derived class, just capture 'this' for arrow functions if necessary. if (!hasExtendsClause) { if (ctor) { - addCaptureThisForNodeIfNeeded(statements, ctor, enableSubstitutionsForCapturedThis); + addCaptureThisForNodeIfNeeded(statements, ctor); } return SuperCaptureResult.NoReplacement; } @@ -1016,7 +1016,7 @@ namespace ts { } // Perform the capture. - captureThisForNode(statements, ctor, superCallExpression, enableSubstitutionsForCapturedThis, firstStatement); + captureThisForNode(statements, ctor, superCallExpression, firstStatement); // If we're actually replacing the original statement, we need to signal this to the caller. if (superCallExpression) { @@ -1085,6 +1085,250 @@ namespace ts { } } + /** + * Gets a value indicating whether we need to add default value assignments for a + * function-like node. + * + * @param node A function-like node. + */ + function shouldAddDefaultValueAssignments(node: FunctionLikeDeclaration): boolean { + return (node.transformFlags & TransformFlags.ContainsDefaultValueAssignments) !== 0; + } + + /** + * Adds statements to the body of a function-like node if it contains parameters with + * binding patterns or initializers. + * + * @param statements The statements for the new function body. + * @param node A function-like node. + */ + function addDefaultValueAssignmentsIfNeeded(statements: Statement[], node: FunctionLikeDeclaration): void { + if (!shouldAddDefaultValueAssignments(node)) { + return; + } + + for (const parameter of node.parameters) { + const { name, initializer, dotDotDotToken } = parameter; + + // A rest parameter cannot have a binding pattern or an initializer, + // so let's just ignore it. + if (dotDotDotToken) { + continue; + } + + if (isBindingPattern(name)) { + addDefaultValueAssignmentForBindingPattern(statements, parameter, name, initializer); + } + else if (initializer) { + addDefaultValueAssignmentForInitializer(statements, parameter, name, initializer); + } + } + } + + /** + * Adds statements to the body of a function-like node for parameters with binding patterns + * + * @param statements The statements for the new function body. + * @param parameter The parameter for the function. + * @param name The name of the parameter. + * @param initializer The initializer for the parameter. + */ + function addDefaultValueAssignmentForBindingPattern(statements: Statement[], parameter: ParameterDeclaration, name: BindingPattern, initializer: Expression): void { + const temp = getGeneratedNameForNode(parameter); + + // In cases where a binding pattern is simply '[]' or '{}', + // we usually don't want to emit a var declaration; however, in the presence + // of an initializer, we must emit that expression to preserve side effects. + if (name.elements.length > 0) { + statements.push( + setEmitFlags( + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList( + flattenDestructuringBinding( + context, + parameter, + temp, + /*skipInitializer*/ false, + /*recordTempVariablesInLine*/ true, + FlattenLevel.All, + visitor + ) + ) + ), + EmitFlags.CustomPrologue + ) + ); + } + else if (initializer) { + statements.push( + setEmitFlags( + createStatement( + createAssignment( + temp, + visitNode(initializer, visitor, isExpression) + ) + ), + EmitFlags.CustomPrologue + ) + ); + } + } + + /** + * Adds statements to the body of a function-like node for parameters with initializers. + * + * @param statements The statements for the new function body. + * @param parameter The parameter for the function. + * @param name The name of the parameter. + * @param initializer The initializer for the parameter. + */ + function addDefaultValueAssignmentForInitializer(statements: Statement[], parameter: ParameterDeclaration, name: Identifier, initializer: Expression): void { + initializer = visitNode(initializer, visitor, isExpression); + const statement = createIf( + createStrictEquality( + getSynthesizedClone(name), + createVoidZero() + ), + setEmitFlags( + createBlock([ + createStatement( + createAssignment( + setEmitFlags(getMutableClone(name), EmitFlags.NoSourceMap), + setEmitFlags(initializer, EmitFlags.NoSourceMap | getEmitFlags(initializer)), + /*location*/ parameter + ) + ) + ], /*location*/ parameter), + EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps + ), + /*elseStatement*/ undefined, + /*location*/ parameter + ); + statement.startsOnNewLine = true; + setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue); + statements.push(statement); + } + + /** + * Gets a value indicating whether we need to add statements to handle a rest parameter. + * + * @param node A ParameterDeclaration node. + * @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is + * part of a constructor declaration with a + * synthesized call to `super` + */ + function shouldAddRestParameter(node: ParameterDeclaration, inConstructorWithSynthesizedSuper: boolean) { + return node && node.dotDotDotToken && node.name.kind === SyntaxKind.Identifier && !inConstructorWithSynthesizedSuper; + } + + /** + * Adds statements to the body of a function-like node if it contains a rest parameter. + * + * @param statements The statements for the new function body. + * @param node A function-like node. + * @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is + * part of a constructor declaration with a + * synthesized call to `super` + */ + function addRestParameterIfNeeded(statements: Statement[], node: FunctionLikeDeclaration, inConstructorWithSynthesizedSuper: boolean): void { + const parameter = lastOrUndefined(node.parameters); + if (!shouldAddRestParameter(parameter, inConstructorWithSynthesizedSuper)) { + return; + } + + // `declarationName` is the name of the local declaration for the parameter. + const declarationName = getMutableClone(parameter.name); + setEmitFlags(declarationName, EmitFlags.NoSourceMap); + + // `expressionName` is the name of the parameter used in expressions. + const expressionName = getSynthesizedClone(parameter.name); + const restIndex = node.parameters.length - 1; + const temp = createLoopVariable(); + + // var param = []; + statements.push( + setEmitFlags( + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + declarationName, + /*type*/ undefined, + createArrayLiteral([]) + ) + ]), + /*location*/ parameter + ), + EmitFlags.CustomPrologue + ) + ); + + // for (var _i = restIndex; _i < arguments.length; _i++) { + // param[_i - restIndex] = arguments[_i]; + // } + const forStatement = createFor( + createVariableDeclarationList([ + createVariableDeclaration(temp, /*type*/ undefined, createLiteral(restIndex)) + ], /*location*/ parameter), + createLessThan( + temp, + createPropertyAccess(createIdentifier("arguments"), "length"), + /*location*/ parameter + ), + createPostfixIncrement(temp, /*location*/ parameter), + createBlock([ + startOnNewLine( + createStatement( + createAssignment( + createElementAccess( + expressionName, + createSubtract(temp, createLiteral(restIndex)) + ), + createElementAccess(createIdentifier("arguments"), temp) + ), + /*location*/ parameter + ) + ) + ]) + ); + + setEmitFlags(forStatement, EmitFlags.CustomPrologue); + startOnNewLine(forStatement); + statements.push(forStatement); + } + + /** + * Adds a statement to capture the `this` of a function declaration if it is needed. + * + * @param statements The statements for the new function body. + * @param node A node. + */ + function addCaptureThisForNodeIfNeeded(statements: Statement[], node: Node): void { + if (node.transformFlags & TransformFlags.ContainsCapturedLexicalThis && node.kind !== SyntaxKind.ArrowFunction) { + captureThisForNode(statements, node, createThis()); + } + } + + function captureThisForNode(statements: Statement[], node: Node, initializer: Expression | undefined, originalStatement?: Statement): void { + enableSubstitutionsForCapturedThis(); + const captureThisStatement = createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + "_this", + /*type*/ undefined, + initializer + ) + ]), + originalStatement + ); + + setEmitFlags(captureThisStatement, EmitFlags.NoComments | EmitFlags.CustomPrologue); + setSourceMapRange(captureThisStatement, node); + statements.push(captureThisStatement); + } + /** * Adds statements to the class body function for a class to define the members of the * class. @@ -1282,7 +1526,7 @@ namespace ts { /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, - transformFunctionBody(node, visitor, currentSourceFile, context, enableSubstitutionsForCapturedThis), + transformFunctionBody(node), /*location*/ node ), /*original*/ node); @@ -1309,7 +1553,7 @@ namespace ts { /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, - saveStateAndInvoke(node, node => transformFunctionBody(node, visitor, currentSourceFile, context, enableSubstitutionsForCapturedThis)), + saveStateAndInvoke(node, transformFunctionBody), location ), /*original*/ node @@ -1319,6 +1563,96 @@ namespace ts { return expression; } + /** + * Transforms the body of a function-like node. + * + * @param node A function-like node. + */ + function transformFunctionBody(node: FunctionLikeDeclaration) { + let multiLine = false; // indicates whether the block *must* be emitted as multiple lines + let singleLine = false; // indicates whether the block *may* be emitted as a single line + let statementsLocation: TextRange; + let closeBraceLocation: TextRange; + + const statements: Statement[] = []; + const body = node.body; + let statementOffset: number; + + context.startLexicalEnvironment(); + if (isBlock(body)) { + // ensureUseStrict is false because no new prologue-directive should be added. + // addPrologueDirectives will simply put already-existing directives at the beginning of the target statement-array + statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor); + } + + addCaptureThisForNodeIfNeeded(statements, node); + addDefaultValueAssignmentsIfNeeded(statements, node); + addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false); + + // If we added any generated statements, this must be a multi-line block. + if (!multiLine && statements.length > 0) { + multiLine = true; + } + + if (isBlock(body)) { + statementsLocation = body.statements; + addRange(statements, visitNodes(body.statements, visitor, isStatement, statementOffset)); + + // If the original body was a multi-line block, this must be a multi-line block. + if (!multiLine && body.multiLine) { + multiLine = true; + } + } + else { + Debug.assert(node.kind === SyntaxKind.ArrowFunction); + + // To align with the old emitter, we use a synthetic end position on the location + // for the statement list we synthesize when we down-level an arrow function with + // an expression function body. This prevents both comments and source maps from + // being emitted for the end position only. + statementsLocation = moveRangeEnd(body, -1); + + const equalsGreaterThanToken = (node).equalsGreaterThanToken; + if (!nodeIsSynthesized(equalsGreaterThanToken) && !nodeIsSynthesized(body)) { + if (rangeEndIsOnSameLineAsRangeStart(equalsGreaterThanToken, body, currentSourceFile)) { + singleLine = true; + } + else { + multiLine = true; + } + } + + const expression = visitNode(body, visitor, isExpression); + const returnStatement = createReturn(expression, /*location*/ body); + setEmitFlags(returnStatement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTrailingComments); + statements.push(returnStatement); + + // To align with the source map emit for the old emitter, we set a custom + // source map location for the close brace. + closeBraceLocation = body; + } + + const lexicalEnvironment = context.endLexicalEnvironment(); + addRange(statements, lexicalEnvironment); + + // If we added any final generated statements, this must be a multi-line block + if (!multiLine && lexicalEnvironment && lexicalEnvironment.length) { + multiLine = true; + } + + const block = createBlock(createNodeArray(statements, statementsLocation), node.body, multiLine); + if (!multiLine && singleLine) { + setEmitFlags(block, EmitFlags.SingleLine); + } + + if (closeBraceLocation) { + setTokenSourceMapRange(block, SyntaxKind.CloseBraceToken, closeBraceLocation); + } + + setOriginalNode(block, node.body); + return block; + } + /** * Visits an ExpressionStatement that contains a destructuring assignment. * @@ -1606,7 +1940,177 @@ namespace ts { } function convertForOfToFor(node: ForOfStatement, convertedLoopBodyStatements: Statement[]): ForStatement { - return convertForOf(node, convertedLoopBodyStatements, visitor, enableSubstitutionsForBlockScopedBindings, context, /*transformRest*/ false); + // The following ES6 code: + // + // for (let v of expr) { } + // + // should be emitted as + // + // for (var _i = 0, _a = expr; _i < _a.length; _i++) { + // var v = _a[_i]; + // } + // + // where _a and _i are temps emitted to capture the RHS and the counter, + // respectively. + // When the left hand side is an expression instead of a let declaration, + // the "let v" is not emitted. + // When the left hand side is a let/const, the v is renamed if there is + // another v in scope. + // Note that all assignments to the LHS are emitted in the body, including + // all destructuring. + // Note also that because an extra statement is needed to assign to the LHS, + // for-of bodies are always emitted as blocks. + + const expression = visitNode(node.expression, visitor, isExpression); + const initializer = node.initializer; + const statements: Statement[] = []; + + // In the case where the user wrote an identifier as the RHS, like this: + // + // for (let v of arr) { } + // + // we don't want to emit a temporary variable for the RHS, just use it directly. + const counter = createLoopVariable(); + const rhsReference = expression.kind === SyntaxKind.Identifier + ? createUniqueName((expression).text) + : createTempVariable(/*recordTempVariable*/ undefined); + const elementAccess = createElementAccess(rhsReference, counter); + + // Initialize LHS + // var v = _a[_i]; + if (isVariableDeclarationList(initializer)) { + if (initializer.flags & NodeFlags.BlockScoped) { + enableSubstitutionsForBlockScopedBindings(); + } + + const firstOriginalDeclaration = firstOrUndefined(initializer.declarations); + if (firstOriginalDeclaration && isBindingPattern(firstOriginalDeclaration.name)) { + // This works whether the declaration is a var, let, or const. + // It will use rhsIterationValue _a[_i] as the initializer. + const declarations = flattenDestructuringBinding( + context, + firstOriginalDeclaration, + elementAccess, + /*skipInitializer*/ false, + /*recordTempVariablesInLine*/ true, + FlattenLevel.All, + visitor + ); + + const declarationList = createVariableDeclarationList(declarations, /*location*/ initializer); + setOriginalNode(declarationList, initializer); + + // Adjust the source map range for the first declaration to align with the old + // emitter. + const firstDeclaration = declarations[0]; + const lastDeclaration = lastOrUndefined(declarations); + setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end)); + + statements.push( + createVariableStatement( + /*modifiers*/ undefined, + declarationList + ) + ); + } + else { + // The following call does not include the initializer, so we have + // to emit it separately. + statements.push( + createVariableStatement( + /*modifiers*/ undefined, + setOriginalNode( + createVariableDeclarationList([ + createVariableDeclaration( + firstOriginalDeclaration ? firstOriginalDeclaration.name : createTempVariable(/*recordTempVariable*/ undefined), + /*type*/ undefined, + createElementAccess(rhsReference, counter) + ) + ], /*location*/ moveRangePos(initializer, -1)), + initializer + ), + /*location*/ moveRangeEnd(initializer, -1) + ) + ); + } + } + else { + // Initializer is an expression. Emit the expression in the body, so that it's + // evaluated on every iteration. + const assignment = createAssignment(initializer, elementAccess); + if (isDestructuringAssignment(assignment)) { + // This is a destructuring pattern, so we flatten the destructuring instead. + statements.push( + createStatement( + flattenDestructuringAssignment( + context, + assignment, + /*needsValue*/ false, + FlattenLevel.All, + /*createAssignmentCallback*/ undefined, + visitor + ) + ) + ); + } + else { + // Currently there is not way to check that assignment is binary expression of destructing assignment + // so we have to cast never type to binaryExpression + (assignment).end = initializer.end; + statements.push(createStatement(assignment, /*location*/ moveRangeEnd(initializer, -1))); + } + } + + let bodyLocation: TextRange; + let statementsLocation: TextRange; + if (convertedLoopBodyStatements) { + addRange(statements, convertedLoopBodyStatements); + } + else { + const statement = visitNode(node.statement, visitor, isStatement); + if (isBlock(statement)) { + addRange(statements, statement.statements); + bodyLocation = statement; + statementsLocation = statement.statements; + } + else { + statements.push(statement); + } + } + + // The old emitter does not emit source maps for the expression + setEmitFlags(expression, EmitFlags.NoSourceMap | getEmitFlags(expression)); + + // The old emitter does not emit source maps for the block. + // We add the location to preserve comments. + const body = createBlock( + createNodeArray(statements, /*location*/ statementsLocation), + /*location*/ bodyLocation + ); + + setEmitFlags(body, EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps); + + const forStatement = createFor( + setEmitFlags( + createVariableDeclarationList([ + createVariableDeclaration(counter, /*type*/ undefined, createLiteral(0), /*location*/ moveRangePos(node.expression, -1)), + createVariableDeclaration(rhsReference, /*type*/ undefined, expression, /*location*/ node.expression) + ], /*location*/ node.expression), + EmitFlags.NoHoisting + ), + createLessThan( + counter, + createPropertyAccess(rhsReference, "length"), + /*location*/ node.expression + ), + createPostfixIncrement(counter, /*location*/ node.expression), + body, + /*location*/ node + ); + + // Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter. + setEmitFlags(forStatement, EmitFlags.NoTokenTrailingSourceMaps); + return forStatement; } /** @@ -2592,7 +3096,7 @@ namespace ts { const statements: Statement[] = []; startLexicalEnvironment(); addRange(statements, prologue); - addCaptureThisForNodeIfNeeded(statements, node, enableSubstitutionsForCapturedThis); + addCaptureThisForNodeIfNeeded(statements, node); addRange(statements, visitNodes(createNodeArray(remaining), visitor, isStatement)); addRange(statements, endLexicalEnvironment()); const clone = getMutableClone(node); diff --git a/src/compiler/transformers/es2016.ts b/src/compiler/transformers/es2016.ts index 56d7fb0249a..5959753fcef 100644 --- a/src/compiler/transformers/es2016.ts +++ b/src/compiler/transformers/es2016.ts @@ -17,84 +17,75 @@ namespace ts { } function visitor(node: Node): VisitResult { - if (node.transformFlags & TransformFlags.ES2016) { - return visitorWorker(node); - } - else if (node.transformFlags & TransformFlags.ContainsES2016) { - return visitEachChild(node, visitor, context); - } - else { + if ((node.transformFlags & TransformFlags.ContainsES2016) === 0) { return node; } - } - - function visitorWorker(node: Node): VisitResult { switch (node.kind) { case SyntaxKind.BinaryExpression: return visitBinaryExpression(node); default: - Debug.failBadSyntaxKind(node); return visitEachChild(node, visitor, context); } } function visitBinaryExpression(node: BinaryExpression): Expression { - // We are here because ES2016 adds support for the exponentiation operator. + switch (node.operatorToken.kind) { + case SyntaxKind.AsteriskAsteriskEqualsToken: + return visitExponentiationAssignmentExpression(node); + case SyntaxKind.AsteriskAsteriskToken: + return visitExponentiationExpression(node); + default: + return visitEachChild(node, visitor, context); + } + } + + function visitExponentiationAssignmentExpression(node: BinaryExpression) { + let target: Expression; + let value: Expression; const left = visitNode(node.left, visitor, isExpression); const right = visitNode(node.right, visitor, isExpression); - if (node.operatorToken.kind === SyntaxKind.AsteriskAsteriskEqualsToken) { - let target: Expression; - let value: Expression; - if (isElementAccessExpression(left)) { - // Transforms `a[x] **= b` into `(_a = a)[_x = x] = Math.pow(_a[_x], b)` - const expressionTemp = createTempVariable(hoistVariableDeclaration); - - const argumentExpressionTemp = createTempVariable(hoistVariableDeclaration); - - target = createElementAccess( - createAssignment(expressionTemp, left.expression, /*location*/ left.expression), - createAssignment(argumentExpressionTemp, left.argumentExpression, /*location*/ left.argumentExpression), - /*location*/ left - ); - - value = createElementAccess( - expressionTemp, - argumentExpressionTemp, - /*location*/ left - ); - } - else if (isPropertyAccessExpression(left)) { - // Transforms `a.x **= b` into `(_a = a).x = Math.pow(_a.x, b)` - const expressionTemp = createTempVariable(hoistVariableDeclaration); - - target = createPropertyAccess( - createAssignment(expressionTemp, left.expression, /*location*/ left.expression), - left.name, - /*location*/ left - ); - - value = createPropertyAccess( - expressionTemp, - left.name, - /*location*/ left - ); - } - else { - // Transforms `a **= b` into `a = Math.pow(a, b)` - target = left; - value = left; - } - - return createAssignment(target, createMathPow(value, right, /*location*/ node), /*location*/ node); + if (isElementAccessExpression(left)) { + // Transforms `a[x] **= b` into `(_a = a)[_x = x] = Math.pow(_a[_x], b)` + const expressionTemp = createTempVariable(hoistVariableDeclaration); + const argumentExpressionTemp = createTempVariable(hoistVariableDeclaration); + target = createElementAccess( + createAssignment(expressionTemp, left.expression, /*location*/ left.expression), + createAssignment(argumentExpressionTemp, left.argumentExpression, /*location*/ left.argumentExpression), + /*location*/ left + ); + value = createElementAccess( + expressionTemp, + argumentExpressionTemp, + /*location*/ left + ); } - else if (node.operatorToken.kind === SyntaxKind.AsteriskAsteriskToken) { - // Transforms `a ** b` into `Math.pow(a, b)` - return createMathPow(left, right, /*location*/ node); + else if (isPropertyAccessExpression(left)) { + // Transforms `a.x **= b` into `(_a = a).x = Math.pow(_a.x, b)` + const expressionTemp = createTempVariable(hoistVariableDeclaration); + target = createPropertyAccess( + createAssignment(expressionTemp, left.expression, /*location*/ left.expression), + left.name, + /*location*/ left + ); + value = createPropertyAccess( + expressionTemp, + left.name, + /*location*/ left + ); } else { - Debug.failBadSyntaxKind(node); - return visitEachChild(node, visitor, context); + // Transforms `a **= b` into `a = Math.pow(a, b)` + target = left; + value = left; } + return createAssignment(target, createMathPow(value, right, /*location*/ node), /*location*/ node); + } + + function visitExponentiationExpression(node: BinaryExpression) { + // Transforms `a ** b` into `Math.pow(a, b)` + const left = visitNode(node.left, visitor, isExpression); + const right = visitNode(node.right, visitor, isExpression); + return createMathPow(left, right, /*location*/ node); } } } diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 2a7fb855a92..757fd7957c9 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -7,39 +7,38 @@ namespace ts { const { endLexicalEnvironment } = context; - let currentSourceFile: SourceFile; return transformSourceFile; function transformSourceFile(node: SourceFile) { - currentSourceFile = node; return visitEachChild(node, visitor, context); } function visitor(node: Node): VisitResult { - if (node.transformFlags & TransformFlags.ESNext) { - return visitorWorker(node); - } - else if (node.transformFlags & TransformFlags.ContainsESNext) { - return visitNodeContainingESNext(node); - } - else { - return node; - } + return visitorWorker(node, /*noDestructuringValue*/ false); } - function visitorWorker(node: Node): VisitResult { + function visitorNoDestructuringValue(node: Node): VisitResult { + return visitorWorker(node, /*noDestructuringValue*/ true); + } + + function visitorWorker(node: Node, noDestructuringValue: boolean): VisitResult { + if ((node.transformFlags & TransformFlags.ContainsESNext) === 0) { + return node; + } + switch (node.kind) { case SyntaxKind.ObjectLiteralExpression: return visitObjectLiteralExpression(node as ObjectLiteralExpression); case SyntaxKind.BinaryExpression: - return visitBinaryExpression(node as BinaryExpression, /*needsDestructuringValue*/ true); + return visitBinaryExpression(node as BinaryExpression, noDestructuringValue); case SyntaxKind.VariableDeclaration: return visitVariableDeclaration(node as VariableDeclaration); case SyntaxKind.ForOfStatement: return visitForOfStatement(node as ForOfStatement); - case SyntaxKind.ObjectBindingPattern: - case SyntaxKind.ArrayBindingPattern: - return node; + case SyntaxKind.ForStatement: + return visitForStatement(node as ForStatement); + case SyntaxKind.VoidExpression: + return visitVoidExpression(node as VoidExpression); case SyntaxKind.Constructor: return visitConstructorDeclaration(node as ConstructorDeclaration); case SyntaxKind.MethodDeclaration: @@ -56,20 +55,13 @@ namespace ts { return visitArrowFunction(node as ArrowFunction); case SyntaxKind.Parameter: return visitParameter(node as ParameterDeclaration); - default: - Debug.failBadSyntaxKind(node); - return visitEachChild(node, visitor, context); - } - } - - function visitNodeContainingESNext(node: Node) { - switch (node.kind) { case SyntaxKind.ExpressionStatement: return visitExpressionStatement(node as ExpressionStatement); case SyntaxKind.ParenthesizedExpression: - return visitParenthesizedExpression(node as ParenthesizedExpression, /*needsDestructuringValue*/ true); + return visitParenthesizedExpression(node as ParenthesizedExpression, noDestructuringValue); + default: + return visitEachChild(node, visitor, context); } - return visitEachChild(node, visitor, context); } function chunkObjectLiteralElements(elements: ObjectLiteralElement[]): Expression[] { @@ -105,38 +97,27 @@ namespace ts { } function visitObjectLiteralExpression(node: ObjectLiteralExpression): Expression { - // spread elements emit like so: - // non-spread elements are chunked together into object literals, and then all are passed to __assign: - // { a, ...o, b } => __assign({a}, o, {b}); - // If the first element is a spread element, then the first argument to __assign is {}: - // { ...o, a, b, ...o2 } => __assign({}, o, {a, b}, o2) - const objects = chunkObjectLiteralElements(node.properties); - if (objects.length && objects[0].kind !== SyntaxKind.ObjectLiteralExpression) { - objects.unshift(createObjectLiteral()); + if (node.transformFlags & TransformFlags.ContainsObjectSpread) { + // spread elements emit like so: + // non-spread elements are chunked together into object literals, and then all are passed to __assign: + // { a, ...o, b } => __assign({a}, o, {b}); + // If the first element is a spread element, then the first argument to __assign is {}: + // { ...o, a, b, ...o2 } => __assign({}, o, {a, b}, o2) + const objects = chunkObjectLiteralElements(node.properties); + if (objects.length && objects[0].kind !== SyntaxKind.ObjectLiteralExpression) { + objects.unshift(createObjectLiteral()); + } + return createCall(createIdentifier("__assign"), undefined, objects); } - return createCall(createIdentifier("__assign"), undefined, objects); + return visitEachChild(node, visitor, context); } function visitExpressionStatement(node: ExpressionStatement): ExpressionStatement { - switch (node.expression.kind) { - case SyntaxKind.ParenthesizedExpression: - return updateStatement(node, visitParenthesizedExpression(node.expression, /*needsDestructuringValue*/ false)); - case SyntaxKind.BinaryExpression: - return updateStatement(node, visitBinaryExpression(node.expression, /*needsDestructuringValue*/ false)); - } - return visitEachChild(node, visitor, context); + return visitEachChild(node, visitorNoDestructuringValue, context); } - function visitParenthesizedExpression(node: ParenthesizedExpression, needsDestructuringValue: boolean): ParenthesizedExpression { - if (!needsDestructuringValue) { - switch (node.expression.kind) { - case SyntaxKind.ParenthesizedExpression: - return updateParen(node, visitParenthesizedExpression(node.expression, /*needsDestructuringValue*/ false)); - case SyntaxKind.BinaryExpression: - return updateParen(node, visitBinaryExpression(node.expression, /*needsDestructuringValue*/ false)); - } - } - return visitEachChild(node, visitor, context); + function visitParenthesizedExpression(node: ParenthesizedExpression, noDestructuringValue: boolean): ParenthesizedExpression { + return visitEachChild(node, noDestructuringValue ? visitorNoDestructuringValue : visitor, context); } /** @@ -144,17 +125,24 @@ namespace ts { * * @param node A BinaryExpression node. */ - function visitBinaryExpression(node: BinaryExpression, needsDestructuringValue: boolean): Expression { + function visitBinaryExpression(node: BinaryExpression, noDestructuringValue: boolean): Expression { if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.ContainsObjectRest) { return flattenDestructuringAssignment( context, node, - needsDestructuringValue, + !noDestructuringValue, FlattenLevel.ObjectRest, /*createAssignmentCallback*/ undefined, visitor ); } + else if (node.operatorToken.kind === SyntaxKind.CommaToken) { + return updateBinary( + node, + visitNode(node.left, visitorNoDestructuringValue, isExpression), + visitNode(node.right, noDestructuringValue ? visitorNoDestructuringValue : visitor, isExpression) + ); + } return visitEachChild(node, visitor, context); } @@ -178,6 +166,20 @@ namespace ts { return visitEachChild(node, visitor, context); } + function visitForStatement(node: ForStatement): VisitResult { + return updateFor( + node, + visitNode(node.initializer, visitorNoDestructuringValue, isForInitializer), + visitNode(node.condition, visitor, isExpression), + visitNode(node.incrementor, visitor, isExpression), + visitNode(node.statement, visitor, isStatement) + ); + } + + function visitVoidExpression(node: VoidExpression) { + return visitEachChild(node, visitorNoDestructuringValue, context); + } + /** * Visits a ForOfStatement and converts it into a ES2015-compatible ForOfStatement. * diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8a6e74030d5..b22fba32da9 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2721,7 +2721,7 @@ namespace ts { resolvedSignature?: Signature; // Cached signature of signature node or call expression resolvedSymbol?: Symbol; // Cached name resolution result resolvedIndexInfo?: IndexInfo; // Cached indexing info resolution result - maybeTypePredicate?: boolean; // Cached check whether call expression might reference a type predicate + maybeTypePredicate?: boolean; // Cached check whether call expression might reference a type predicate enumMemberValue?: number; // Constant value of enum member isVisible?: boolean; // Is this node visible hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context @@ -3558,36 +3558,34 @@ namespace ts { TypeScript = 1 << 0, ContainsTypeScript = 1 << 1, ContainsJsx = 1 << 2, - ESNext = 1 << 3, - ContainsESNext = 1 << 4, - ContainsES2017 = 1 << 5, - ES2016 = 1 << 6, - ContainsES2016 = 1 << 7, - ES2015 = 1 << 8, - ContainsES2015 = 1 << 9, - Generator = 1 << 10, - ContainsGenerator = 1 << 11, - DestructuringAssignment = 1 << 12, - ContainsDestructuringAssignment = 1 << 13, + ContainsESNext = 1 << 3, + ContainsES2017 = 1 << 4, + ContainsES2016 = 1 << 5, + ES2015 = 1 << 6, + ContainsES2015 = 1 << 7, + Generator = 1 << 8, + ContainsGenerator = 1 << 9, + DestructuringAssignment = 1 << 10, + ContainsDestructuringAssignment = 1 << 11, // Markers // - Flags used to indicate that a subtree contains a specific transformation. - ContainsDecorators = 1 << 14, - ContainsPropertyInitializer = 1 << 15, - ContainsLexicalThis = 1 << 16, - ContainsCapturedLexicalThis = 1 << 17, - ContainsLexicalThisInComputedPropertyName = 1 << 18, - ContainsDefaultValueAssignments = 1 << 19, - ContainsParameterPropertyAssignments = 1 << 20, - ContainsSpread = 1 << 21, + ContainsDecorators = 1 << 12, + ContainsPropertyInitializer = 1 << 13, + ContainsLexicalThis = 1 << 14, + ContainsCapturedLexicalThis = 1 << 15, + ContainsLexicalThisInComputedPropertyName = 1 << 16, + ContainsDefaultValueAssignments = 1 << 17, + ContainsParameterPropertyAssignments = 1 << 18, + ContainsSpread = 1 << 19, + ContainsObjectSpread = 1 << 20, ContainsRest = ContainsSpread, - ContainsObjectSpread = 1 << 22, ContainsObjectRest = ContainsObjectSpread, - ContainsComputedPropertyName = 1 << 23, - ContainsBlockScopedBinding = 1 << 24, - ContainsBindingPattern = 1 << 25, - ContainsYield = 1 << 26, - ContainsHoistedDeclarationOrCompletion = 1 << 27, + ContainsComputedPropertyName = 1 << 21, + ContainsBlockScopedBinding = 1 << 22, + ContainsBindingPattern = 1 << 23, + ContainsYield = 1 << 24, + ContainsHoistedDeclarationOrCompletion = 1 << 25, HasComputedFlags = 1 << 29, // Transform flags have been computed. @@ -3595,9 +3593,9 @@ namespace ts { // - Bitmasks that are used to assert facts about the syntax of a node and its subtree. AssertTypeScript = TypeScript | ContainsTypeScript, AssertJsx = ContainsJsx, - AssertESNext = ESNext | ContainsESNext, + AssertESNext = ContainsESNext, AssertES2017 = ContainsES2017, - AssertES2016 = ES2016 | ContainsES2016, + AssertES2016 = ContainsES2016, AssertES2015 = ES2015 | ContainsES2015, AssertGenerator = Generator | ContainsGenerator, AssertDestructuringAssignment = DestructuringAssignment | ContainsDestructuringAssignment, @@ -3605,7 +3603,7 @@ namespace ts { // Scope Exclusions // - Bitmasks that exclude flags from propagating out of a specific context // into the subtree flags of their container. - NodeExcludes = TypeScript | ESNext | ES2016 | ES2015 | DestructuringAssignment | Generator | HasComputedFlags, + NodeExcludes = TypeScript | ES2015 | DestructuringAssignment | Generator | HasComputedFlags, ArrowFunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRest, FunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRest, ConstructorExcludes = NodeExcludes | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRest, diff --git a/tests/baselines/reference/objectRestForOf.js b/tests/baselines/reference/objectRestForOf.js index 26ebd8f8229..f8872ffbae4 100644 --- a/tests/baselines/reference/objectRestForOf.js +++ b/tests/baselines/reference/objectRestForOf.js @@ -30,14 +30,14 @@ var __rest = (this && this.__rest) || function (s, e) { return t; }; let array; -for (var array_1 of array) { - var { x } = array_1, restOf = __rest(array_1, ["x"]); +for (let _a of array) { + let { x } = _a, restOf = __rest(_a, ["x"]); [x, restOf]; } let xx; let rrestOff; -for (var array_2 of array) { - ({ x: xx } = array_2, rrestOff = __rest(array_2, ["x"])); +for (let _b of array) { + ({ x: xx } = _b, rrestOff = __rest(_b, ["x"])); [xx, rrestOff]; } for (const norest of array.map(a => (__assign({}, a, { x: 'a string' })))) { diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js b/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js index 8355d61d9c3..9f7a70699bd 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js +++ b/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js @@ -194,13 +194,13 @@ for (_b = getRobot(), _c = _b.name, nameA = _c === void 0 ? "noName" : _c, _b, i for (_d = { name: "trimmer", skill: "trimming" }, _e = _d.name, nameA = _e === void 0 ? "noName" : _e, _d, i = 0; i < 1; i++) { console.log(nameA); } -for (_f = multiRobot.skills, _g = _f === void 0 ? { primary: "none", secondary: "none" } : _f, _h = _g.primary, primaryA = _h === void 0 ? "primary" : _h, _j = _g.secondary, secondaryA = _j === void 0 ? "secondary" : _j, multiRobot, multiRobot, i = 0; i < 1; i++) { +for (_f = multiRobot.skills, _g = _f === void 0 ? { primary: "none", secondary: "none" } : _f, _h = _g.primary, primaryA = _h === void 0 ? "primary" : _h, _j = _g.secondary, secondaryA = _j === void 0 ? "secondary" : _j, multiRobot, i = 0; i < 1; i++) { console.log(primaryA); } -for (_k = getMultiRobot(), (_l = _k.skills, _m = _l === void 0 ? { primary: "none", secondary: "none" } : _l, _o = _m.primary, primaryA = _o === void 0 ? "primary" : _o, _p = _m.secondary, secondaryA = _p === void 0 ? "secondary" : _p, _k), _k, i = 0; i < 1; i++) { +for (_k = getMultiRobot(), _l = _k.skills, _m = _l === void 0 ? { primary: "none", secondary: "none" } : _l, _o = _m.primary, primaryA = _o === void 0 ? "primary" : _o, _p = _m.secondary, secondaryA = _p === void 0 ? "secondary" : _p, _k, i = 0; i < 1; i++) { console.log(primaryA); } -for (_q = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_r = _q.skills, _s = _r === void 0 ? { primary: "none", secondary: "none" } : _r, _t = _s.primary, primaryA = _t === void 0 ? "primary" : _t, _u = _s.secondary, secondaryA = _u === void 0 ? "secondary" : _u, _q), _q, +for (_q = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _r = _q.skills, _s = _r === void 0 ? { primary: "none", secondary: "none" } : _r, _t = _s.primary, primaryA = _t === void 0 ? "primary" : _t, _u = _s.secondary, secondaryA = _u === void 0 ? "secondary" : _u, _q, i = 0; i < 1; i++) { console.log(primaryA); } @@ -213,13 +213,13 @@ for (_w = getRobot(), _x = _w.name, name = _x === void 0 ? "noName" : _x, _w, i for (_y = { name: "trimmer", skill: "trimming" }, _z = _y.name, name = _z === void 0 ? "noName" : _z, _y, i = 0; i < 1; i++) { console.log(nameA); } -for (_0 = multiRobot.skills, _1 = _0 === void 0 ? { primary: "none", secondary: "none" } : _0, _2 = _1.primary, primary = _2 === void 0 ? "primary" : _2, _3 = _1.secondary, secondary = _3 === void 0 ? "secondary" : _3, multiRobot, multiRobot, i = 0; i < 1; i++) { +for (_0 = multiRobot.skills, _1 = _0 === void 0 ? { primary: "none", secondary: "none" } : _0, _2 = _1.primary, primary = _2 === void 0 ? "primary" : _2, _3 = _1.secondary, secondary = _3 === void 0 ? "secondary" : _3, multiRobot, i = 0; i < 1; i++) { console.log(primaryA); } -for (_4 = getMultiRobot(), (_5 = _4.skills, _6 = _5 === void 0 ? { primary: "none", secondary: "none" } : _5, _7 = _6.primary, primary = _7 === void 0 ? "primary" : _7, _8 = _6.secondary, secondary = _8 === void 0 ? "secondary" : _8, _4), _4, i = 0; i < 1; i++) { +for (_4 = getMultiRobot(), _5 = _4.skills, _6 = _5 === void 0 ? { primary: "none", secondary: "none" } : _5, _7 = _6.primary, primary = _7 === void 0 ? "primary" : _7, _8 = _6.secondary, secondary = _8 === void 0 ? "secondary" : _8, _4, i = 0; i < 1; i++) { console.log(primaryA); } -for (_9 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_10 = _9.skills, _11 = _10 === void 0 ? { primary: "none", secondary: "none" } : _10, _12 = _11.primary, primary = _12 === void 0 ? "primary" : _12, _13 = _11.secondary, secondary = _13 === void 0 ? "secondary" : _13, _9), _9, +for (_9 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _10 = _9.skills, _11 = _10 === void 0 ? { primary: "none", secondary: "none" } : _10, _12 = _11.primary, primary = _12 === void 0 ? "primary" : _12, _13 = _11.secondary, secondary = _13 === void 0 ? "secondary" : _13, _9, i = 0; i < 1; i++) { console.log(primaryA); } @@ -232,13 +232,13 @@ for (_16 = getRobot(), _17 = _16.name, nameA = _17 === void 0 ? "noName" : _17, for (_19 = { name: "trimmer", skill: "trimming" }, _20 = _19.name, nameA = _20 === void 0 ? "noName" : _20, _21 = _19.skill, skillA = _21 === void 0 ? "skill" : _21, _19, i = 0; i < 1; i++) { console.log(nameA); } -for (_22 = multiRobot.name, nameA = _22 === void 0 ? "noName" : _22, _23 = multiRobot.skills, _24 = _23 === void 0 ? { primary: "none", secondary: "none" } : _23, _25 = _24.primary, primaryA = _25 === void 0 ? "primary" : _25, _26 = _24.secondary, secondaryA = _26 === void 0 ? "secondary" : _26, multiRobot, multiRobot, i = 0; i < 1; i++) { +for (_22 = multiRobot.name, nameA = _22 === void 0 ? "noName" : _22, _23 = multiRobot.skills, _24 = _23 === void 0 ? { primary: "none", secondary: "none" } : _23, _25 = _24.primary, primaryA = _25 === void 0 ? "primary" : _25, _26 = _24.secondary, secondaryA = _26 === void 0 ? "secondary" : _26, multiRobot, i = 0; i < 1; i++) { console.log(primaryA); } -for (_27 = getMultiRobot(), (_28 = _27.name, nameA = _28 === void 0 ? "noName" : _28, _29 = _27.skills, _30 = _29 === void 0 ? { primary: "none", secondary: "none" } : _29, _31 = _30.primary, primaryA = _31 === void 0 ? "primary" : _31, _32 = _30.secondary, secondaryA = _32 === void 0 ? "secondary" : _32, _27), _27, i = 0; i < 1; i++) { +for (_27 = getMultiRobot(), _28 = _27.name, nameA = _28 === void 0 ? "noName" : _28, _29 = _27.skills, _30 = _29 === void 0 ? { primary: "none", secondary: "none" } : _29, _31 = _30.primary, primaryA = _31 === void 0 ? "primary" : _31, _32 = _30.secondary, secondaryA = _32 === void 0 ? "secondary" : _32, _27, i = 0; i < 1; i++) { console.log(primaryA); } -for (_33 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_34 = _33.name, nameA = _34 === void 0 ? "noName" : _34, _35 = _33.skills, _36 = _35 === void 0 ? { primary: "none", secondary: "none" } : _35, _37 = _36.primary, primaryA = _37 === void 0 ? "primary" : _37, _38 = _36.secondary, secondaryA = _38 === void 0 ? "secondary" : _38, _33), _33, +for (_33 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _34 = _33.name, nameA = _34 === void 0 ? "noName" : _34, _35 = _33.skills, _36 = _35 === void 0 ? { primary: "none", secondary: "none" } : _35, _37 = _36.primary, primaryA = _37 === void 0 ? "primary" : _37, _38 = _36.secondary, secondaryA = _38 === void 0 ? "secondary" : _38, _33, i = 0; i < 1; i++) { console.log(primaryA); } @@ -251,16 +251,15 @@ for (_41 = getRobot(), _42 = _41.name, name = _42 === void 0 ? "noName" : _42, _ for (_44 = { name: "trimmer", skill: "trimming" }, _45 = _44.name, name = _45 === void 0 ? "noName" : _45, _46 = _44.skill, skill = _46 === void 0 ? "skill" : _46, _44, i = 0; i < 1; i++) { console.log(nameA); } -for (_47 = multiRobot.name, name = _47 === void 0 ? "noName" : _47, _48 = multiRobot.skills, _49 = _48 === void 0 ? { primary: "none", secondary: "none" } : _48, _50 = _49.primary, primary = _50 === void 0 ? "primary" : _50, _51 = _49.secondary, secondary = _51 === void 0 ? "secondary" : _51, multiRobot, multiRobot, i = 0; i < 1; i++) { +for (_47 = multiRobot.name, name = _47 === void 0 ? "noName" : _47, _48 = multiRobot.skills, _49 = _48 === void 0 ? { primary: "none", secondary: "none" } : _48, _50 = _49.primary, primary = _50 === void 0 ? "primary" : _50, _51 = _49.secondary, secondary = _51 === void 0 ? "secondary" : _51, multiRobot, i = 0; i < 1; i++) { console.log(primaryA); } -for (_52 = getMultiRobot(), (_53 = _52.name, name = _53 === void 0 ? "noName" : _53, _54 = _52.skills, _55 = _54 === void 0 ? { primary: "none", secondary: "none" } : _54, _56 = _55.primary, primary = _56 === void 0 ? "primary" : _56, _57 = _55.secondary, secondary = _57 === void 0 ? "secondary" : _57, _52), _52, i = 0; i < 1; i++) { +for (_52 = getMultiRobot(), _53 = _52.name, name = _53 === void 0 ? "noName" : _53, _54 = _52.skills, _55 = _54 === void 0 ? { primary: "none", secondary: "none" } : _54, _56 = _55.primary, primary = _56 === void 0 ? "primary" : _56, _57 = _55.secondary, secondary = _57 === void 0 ? "secondary" : _57, _52, i = 0; i < 1; i++) { console.log(primaryA); } -for (_58 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_59 = _58.name, name = _59 === void 0 ? "noName" : _59, _60 = _58.skills, _61 = _60 === void 0 ? { primary: "none", secondary: "none" } : _60, _62 = _61.primary, primary = _62 === void 0 ? "primary" : _62, _63 = _61.secondary, secondary = _63 === void 0 ? "secondary" : _63, _58), _58, +for (_58 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _59 = _58.name, name = _59 === void 0 ? "noName" : _59, _60 = _58.skills, _61 = _60 === void 0 ? { primary: "none", secondary: "none" } : _60, _62 = _61.primary, primary = _62 === void 0 ? "primary" : _62, _63 = _61.secondary, secondary = _63 === void 0 ? "secondary" : _63, _58, i = 0; i < 1; i++) { console.log(primaryA); } -var _k, _q, _4, _9, _27, _33, _52, _58; -var _a, _b, _c, _d, _e, _f, _g, _h, _j, _l, _m, _o, _p, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _5, _6, _7, _8, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _28, _29, _30, _31, _32, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _53, _54, _55, _56, _57, _59, _60, _61, _62, _63; +var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63; //# sourceMappingURL=sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js.map \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js.map b/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js.map index 56f8aa0f607..dd248e89944 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js.map +++ b/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js.map @@ -1,2 +1,2 @@ //// [sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js.map] -{"version":3,"file":"sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js","sourceRoot":"","sources":["sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.ts"],"names":[],"mappings":"AAgBA,IAAI,KAAK,GAAU,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AACtD,IAAI,UAAU,GAAe,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC;AACjG;IACI,MAAM,CAAC,KAAK,CAAC;AACjB,CAAC;AACD;IACI,MAAM,CAAC,UAAU,CAAC;AACtB,CAAC;AAED,IAAI,KAAa,EAAE,QAAgB,EAAE,UAAkB,EAAE,CAAS,EAAE,MAAc,CAAC;AACnF,IAAI,IAAY,EAAE,OAAe,EAAE,SAAiB,EAAE,KAAa,CAAC;AAEpE,GAAG,CAAC,CAAE,eAAsB,EAAtB,qCAAsB,EAAK,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,eAAsC,EAArC,YAAsB,EAAtB,qCAAsB,MAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,2CAAyE,EAAxE,YAAsB,EAAtB,qCAAsB,MAAoD,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CACA,sBAG0C,EAH1C,gEAG0C,EAFtC,eAA6B,EAA7B,yCAA6B,EAC7B,iBAAmC,EAAnC,6CAAmC,EAEvC,UAAU,EAAV,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,oBAKc,GAJf,cAG0C,EAH1C,gEAG0C,EAFtC,eAA6B,EAA7B,yCAA6B,EAC7B,iBAAmC,EAAnC,6CAAmC,WAEtB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,8EAKoF,GAJrF,cAG0C,EAH1C,gEAG0C,EAFtC,eAA6B,EAA7B,yCAA6B,EAC7B,iBAAmC,EAAnC,6CAAmC;IAGvC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AAED,GAAG,CAAC,CAAG,eAAe,EAAf,oCAAe,EAAK,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,eAAgC,EAA9B,YAAe,EAAf,oCAAe,MAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,2CAAmE,EAAjE,YAAe,EAAf,oCAAe,MAAoD,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAC1F,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CACA,sBAG0C,EAH1C,gEAG0C,EAFtC,eAAmB,EAAnB,wCAAmB,EACnB,iBAAuB,EAAvB,4CAAuB,EAE3B,UAAU,EAAV,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,oBAKc,GAJf,cAG0C,EAH1C,gEAG0C,EAFtC,eAAmB,EAAnB,wCAAmB,EACnB,iBAAuB,EAAvB,4CAAuB,WAEV,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,8EAKoF,GAJrF,eAG0C,EAH1C,mEAG0C,EAFtC,iBAAmB,EAAnB,0CAAmB,EACnB,mBAAuB,EAAvB,8CAAuB;IAG3B,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AAGD,GAAG,CAAC,CAAE,gBAAsB,EAAtB,uCAAsB,EAAE,iBAAuB,EAAvB,uCAAuB,EAAK,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACjF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,gBAA+D,EAA9D,cAAsB,EAAtB,uCAAsB,EAAE,eAAuB,EAAvB,uCAAuB,OAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACtF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,4CAAkG,EAAjG,cAAsB,EAAtB,uCAAsB,EAAE,eAAuB,EAAvB,uCAAuB,OAAoD,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACzH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CACA,qBAAsB,EAAtB,uCAAsB,EACtB,uBAG0C,EAH1C,mEAG0C,EAFtC,iBAA6B,EAA7B,2CAA6B,EAC7B,mBAAmC,EAAnC,+CAAmC,EAEvC,UAAU,EAAV,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,qBAMc,GALf,cAAsB,EAAtB,uCAAsB,EACtB,gBAG0C,EAH1C,mEAG0C,EAFtC,iBAA6B,EAA7B,2CAA6B,EAC7B,mBAAmC,EAAnC,+CAAmC,aAEtB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,+EAMoF,GALrF,cAAsB,EAAtB,uCAAsB,EACtB,gBAG0C,EAH1C,mEAG0C,EAFtC,iBAA6B,EAA7B,2CAA6B,EAC7B,mBAAmC,EAAnC,+CAAmC;IAGvC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AAED,GAAG,CAAC,CAAG,gBAAe,EAAf,sCAAe,EAAE,iBAAe,EAAf,sCAAe,EAAK,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,gBAAiD,EAA/C,cAAe,EAAf,sCAAe,EAAE,eAAe,EAAf,sCAAe,OAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACxE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,4CAAoF,EAAlF,cAAe,EAAf,sCAAe,EAAE,eAAe,EAAf,sCAAe,OAAoD,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAC3G,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CACA,qBAAe,EAAf,sCAAe,EACf,uBAG0C,EAH1C,mEAG0C,EAFtC,iBAAmB,EAAnB,0CAAmB,EACnB,mBAAuB,EAAvB,8CAAuB,EAE3B,UAAU,EAAV,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,qBAMc,GALf,cAAe,EAAf,sCAAe,EACf,gBAG0C,EAH1C,mEAG0C,EAFtC,iBAAmB,EAAnB,0CAAmB,EACnB,mBAAuB,EAAvB,8CAAuB,aAEV,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,+EAMoF,GALrF,cAAe,EAAf,sCAAe,EACf,gBAG0C,EAH1C,mEAG0C,EAFtC,iBAAmB,EAAnB,0CAAmB,EACnB,mBAAuB,EAAvB,8CAAuB;IAG3B,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC"} \ No newline at end of file +{"version":3,"file":"sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js","sourceRoot":"","sources":["sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.ts"],"names":[],"mappings":"AAgBA,IAAI,KAAK,GAAU,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AACtD,IAAI,UAAU,GAAe,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC;AACjG;IACI,MAAM,CAAC,KAAK,CAAC;AACjB,CAAC;AACD;IACI,MAAM,CAAC,UAAU,CAAC;AACtB,CAAC;AAED,IAAI,KAAa,EAAE,QAAgB,EAAE,UAAkB,EAAE,CAAS,EAAE,MAAc,CAAC;AACnF,IAAI,IAAY,EAAE,OAAe,EAAE,SAAiB,EAAE,KAAa,CAAC;AAEpE,GAAG,CAAC,CAAE,eAAsB,EAAtB,qCAAsB,EAAK,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,eAAsC,EAArC,YAAsB,EAAtB,qCAAsB,MAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,2CAAyE,EAAxE,YAAsB,EAAtB,qCAAsB,MAAoD,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CACA,sBAG0C,EAH1C,gEAG0C,EAFtC,eAA6B,EAA7B,yCAA6B,EAC7B,iBAAmC,EAAnC,6CAAmC,EAEvC,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,oBAKc,EAJf,cAG0C,EAH1C,gEAG0C,EAFtC,eAA6B,EAA7B,yCAA6B,EAC7B,iBAAmC,EAAnC,6CAAmC,MAEtB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,8EAKoF,EAJrF,cAG0C,EAH1C,gEAG0C,EAFtC,eAA6B,EAA7B,yCAA6B,EAC7B,iBAAmC,EAAnC,6CAAmC;IAGvC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AAED,GAAG,CAAC,CAAG,eAAe,EAAf,oCAAe,EAAK,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,eAAgC,EAA9B,YAAe,EAAf,oCAAe,MAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,2CAAmE,EAAjE,YAAe,EAAf,oCAAe,MAAoD,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAC1F,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CACA,sBAG0C,EAH1C,gEAG0C,EAFtC,eAAmB,EAAnB,wCAAmB,EACnB,iBAAuB,EAAvB,4CAAuB,EAE3B,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,oBAKc,EAJf,cAG0C,EAH1C,gEAG0C,EAFtC,eAAmB,EAAnB,wCAAmB,EACnB,iBAAuB,EAAvB,4CAAuB,MAEV,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,8EAKoF,EAJrF,eAG0C,EAH1C,mEAG0C,EAFtC,iBAAmB,EAAnB,0CAAmB,EACnB,mBAAuB,EAAvB,8CAAuB;IAG3B,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AAGD,GAAG,CAAC,CAAE,gBAAsB,EAAtB,uCAAsB,EAAE,iBAAuB,EAAvB,uCAAuB,EAAK,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACjF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,gBAA+D,EAA9D,cAAsB,EAAtB,uCAAsB,EAAE,eAAuB,EAAvB,uCAAuB,OAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACtF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,4CAAkG,EAAjG,cAAsB,EAAtB,uCAAsB,EAAE,eAAuB,EAAvB,uCAAuB,OAAoD,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACzH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CACA,qBAAsB,EAAtB,uCAAsB,EACtB,uBAG0C,EAH1C,mEAG0C,EAFtC,iBAA6B,EAA7B,2CAA6B,EAC7B,mBAAmC,EAAnC,+CAAmC,EAEvC,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,qBAMc,EALf,cAAsB,EAAtB,uCAAsB,EACtB,gBAG0C,EAH1C,mEAG0C,EAFtC,iBAA6B,EAA7B,2CAA6B,EAC7B,mBAAmC,EAAnC,+CAAmC,OAEtB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,+EAMoF,EALrF,cAAsB,EAAtB,uCAAsB,EACtB,gBAG0C,EAH1C,mEAG0C,EAFtC,iBAA6B,EAA7B,2CAA6B,EAC7B,mBAAmC,EAAnC,+CAAmC;IAGvC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AAED,GAAG,CAAC,CAAG,gBAAe,EAAf,sCAAe,EAAE,iBAAe,EAAf,sCAAe,EAAK,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,gBAAiD,EAA/C,cAAe,EAAf,sCAAe,EAAE,eAAe,EAAf,sCAAe,OAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACxE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,4CAAoF,EAAlF,cAAe,EAAf,sCAAe,EAAE,eAAe,EAAf,sCAAe,OAAoD,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAC3G,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CACA,qBAAe,EAAf,sCAAe,EACf,uBAG0C,EAH1C,mEAG0C,EAFtC,iBAAmB,EAAnB,0CAAmB,EACnB,mBAAuB,EAAvB,8CAAuB,EAE3B,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,qBAMc,EALf,cAAe,EAAf,sCAAe,EACf,gBAG0C,EAH1C,mEAG0C,EAFtC,iBAAmB,EAAnB,0CAAmB,EACnB,mBAAuB,EAAvB,8CAAuB,OAEV,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,+EAMoF,EALrF,cAAe,EAAf,sCAAe,EACf,gBAG0C,EAH1C,mEAG0C,EAFtC,iBAAmB,EAAnB,0CAAmB,EACnB,mBAAuB,EAAvB,8CAAuB;IAG3B,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC"} \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.sourcemap.txt b/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.sourcemap.txt index 9e0e92d4a68..97271e8f3d0 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.sourcemap.txt +++ b/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.sourcemap.txt @@ -594,14 +594,14 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(19, 1) Source(37, 1) + SourceIndex(0) 2 >Emitted(19, 2) Source(37, 2) + SourceIndex(0) --- ->>>for (_f = multiRobot.skills, _g = _f === void 0 ? { primary: "none", secondary: "none" } : _f, _h = _g.primary, primaryA = _h === void 0 ? "primary" : _h, _j = _g.secondary, secondaryA = _j === void 0 ? "secondary" : _j, multiRobot, multiRobot, i = 0; i < 1; i++) { +>>>for (_f = multiRobot.skills, _g = _f === void 0 ? { primary: "none", secondary: "none" } : _f, _h = _g.primary, primaryA = _h === void 0 ? "primary" : _h, _j = _g.secondary, secondaryA = _j === void 0 ? "secondary" : _j, multiRobot, i = 0; i < 1; i++) { 1-> 2 >^^^ 3 > ^ @@ -620,20 +620,18 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 16> ^^ 17> ^^^^^^^^^^ 18> ^^ -19> ^^^^^^^^^^ -20> ^^ -21> ^ -22> ^^^ -23> ^ -24> ^^ -25> ^ -26> ^^^ -27> ^ -28> ^^ -29> ^ -30> ^^ -31> ^^ -32> ^ +19> ^ +20> ^^^ +21> ^ +22> ^^ +23> ^ +24> ^^^ +25> ^ +26> ^^ +27> ^ +28> ^^ +29> ^^ +30> ^ 1-> > 2 >for @@ -662,21 +660,19 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = 17> multiRobot -18> -19> multiRobot -20> , -21> i -22> = -23> 0 -24> ; -25> i -26> < -27> 1 -28> ; -29> i -30> ++ -31> ) -32> { +18> , +19> i +20> = +21> 0 +22> ; +23> i +24> < +25> 1 +26> ; +27> i +28> ++ +29> ) +30> { 1->Emitted(20, 1) Source(38, 1) + SourceIndex(0) 2 >Emitted(20, 4) Source(38, 4) + SourceIndex(0) 3 >Emitted(20, 5) Source(38, 5) + SourceIndex(0) @@ -694,21 +690,19 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 15>Emitted(20, 220) Source(41, 44) + SourceIndex(0) 16>Emitted(20, 222) Source(43, 5) + SourceIndex(0) 17>Emitted(20, 232) Source(43, 15) + SourceIndex(0) -18>Emitted(20, 234) Source(43, 5) + SourceIndex(0) -19>Emitted(20, 244) Source(43, 15) + SourceIndex(0) -20>Emitted(20, 246) Source(43, 17) + SourceIndex(0) -21>Emitted(20, 247) Source(43, 18) + SourceIndex(0) -22>Emitted(20, 250) Source(43, 21) + SourceIndex(0) -23>Emitted(20, 251) Source(43, 22) + SourceIndex(0) -24>Emitted(20, 253) Source(43, 24) + SourceIndex(0) -25>Emitted(20, 254) Source(43, 25) + SourceIndex(0) -26>Emitted(20, 257) Source(43, 28) + SourceIndex(0) -27>Emitted(20, 258) Source(43, 29) + SourceIndex(0) -28>Emitted(20, 260) Source(43, 31) + SourceIndex(0) -29>Emitted(20, 261) Source(43, 32) + SourceIndex(0) -30>Emitted(20, 263) Source(43, 34) + SourceIndex(0) -31>Emitted(20, 265) Source(43, 36) + SourceIndex(0) -32>Emitted(20, 266) Source(43, 37) + SourceIndex(0) +18>Emitted(20, 234) Source(43, 17) + SourceIndex(0) +19>Emitted(20, 235) Source(43, 18) + SourceIndex(0) +20>Emitted(20, 238) Source(43, 21) + SourceIndex(0) +21>Emitted(20, 239) Source(43, 22) + SourceIndex(0) +22>Emitted(20, 241) Source(43, 24) + SourceIndex(0) +23>Emitted(20, 242) Source(43, 25) + SourceIndex(0) +24>Emitted(20, 245) Source(43, 28) + SourceIndex(0) +25>Emitted(20, 246) Source(43, 29) + SourceIndex(0) +26>Emitted(20, 248) Source(43, 31) + SourceIndex(0) +27>Emitted(20, 249) Source(43, 32) + SourceIndex(0) +28>Emitted(20, 251) Source(43, 34) + SourceIndex(0) +29>Emitted(20, 253) Source(43, 36) + SourceIndex(0) +30>Emitted(20, 254) Source(43, 37) + SourceIndex(0) --- >>> console.log(primaryA); 1 >^^^^ @@ -740,44 +734,44 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(22, 1) Source(45, 1) + SourceIndex(0) 2 >Emitted(22, 2) Source(45, 2) + SourceIndex(0) --- ->>>for (_k = getMultiRobot(), (_l = _k.skills, _m = _l === void 0 ? { primary: "none", secondary: "none" } : _l, _o = _m.primary, primaryA = _o === void 0 ? "primary" : _o, _p = _m.secondary, secondaryA = _p === void 0 ? "secondary" : _p, _k), _k, i = 0; i < 1; i++) { +>>>for (_k = getMultiRobot(), _l = _k.skills, _m = _l === void 0 ? { primary: "none", secondary: "none" } : _l, _o = _m.primary, primaryA = _o === void 0 ? "primary" : _o, _p = _m.secondary, secondaryA = _p === void 0 ? "secondary" : _p, _k, i = 0; i < 1; i++) { 1-> 2 >^^^ 3 > ^ 4 > ^ 5 > ^^^^^^^^^^^^^^^^^^^^ -6 > ^^^ -7 > ^^^^^^^^^^^^^^ -8 > ^^ -9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -10> ^^ -11> ^^^^^^^^^^^^^^^ -12> ^^ -13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -14> ^^ -15> ^^^^^^^^^^^^^^^^^ -16> ^^ -17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -18> ^^^^^^^^^^^ -19> ^ -20> ^^^ -21> ^ -22> ^^ -23> ^ -24> ^^^ -25> ^ -26> ^^ -27> ^ -28> ^^ -29> ^^ -30> ^ +6 > ^^ +7 > ^^^^^^^^^^^^^^ +8 > ^^ +9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +10> ^^ +11> ^^^^^^^^^^^^^^^ +12> ^^ +13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +14> ^^ +15> ^^^^^^^^^^^^^^^^^ +16> ^^ +17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +18> ^^^^^^ +19> ^ +20> ^^^ +21> ^ +22> ^^ +23> ^ +24> ^^^ +25> ^ +26> ^^ +27> ^ +28> ^^ +29> ^^ +30> ^ 1-> > 2 >for @@ -790,69 +784,69 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = getMultiRobot() 6 > -7 > skills: { - > primary: primaryA = "primary", - > secondary: secondaryA = "secondary" - > } = { primary: "none", secondary: "none" } -8 > -9 > skills: { - > primary: primaryA = "primary", - > secondary: secondaryA = "secondary" - > } = { primary: "none", secondary: "none" } -10> -11> primary: primaryA = "primary" -12> -13> primary: primaryA = "primary" -14> , - > -15> secondary: secondaryA = "secondary" -16> -17> secondary: secondaryA = "secondary" -18> - > } = { primary: "none", secondary: "none" } - > } = getMultiRobot(), -19> i -20> = -21> 0 -22> ; -23> i -24> < -25> 1 -26> ; -27> i -28> ++ -29> ) -30> { +7 > skills: { + > primary: primaryA = "primary", + > secondary: secondaryA = "secondary" + > } = { primary: "none", secondary: "none" } +8 > +9 > skills: { + > primary: primaryA = "primary", + > secondary: secondaryA = "secondary" + > } = { primary: "none", secondary: "none" } +10> +11> primary: primaryA = "primary" +12> +13> primary: primaryA = "primary" +14> , + > +15> secondary: secondaryA = "secondary" +16> +17> secondary: secondaryA = "secondary" +18> + > } = { primary: "none", secondary: "none" } + > } = getMultiRobot(), +19> i +20> = +21> 0 +22> ; +23> i +24> < +25> 1 +26> ; +27> i +28> ++ +29> ) +30> { 1->Emitted(23, 1) Source(46, 1) + SourceIndex(0) 2 >Emitted(23, 4) Source(46, 4) + SourceIndex(0) 3 >Emitted(23, 5) Source(46, 5) + SourceIndex(0) 4 >Emitted(23, 6) Source(46, 6) + SourceIndex(0) 5 >Emitted(23, 26) Source(51, 20) + SourceIndex(0) -6 >Emitted(23, 29) Source(47, 5) + SourceIndex(0) -7 >Emitted(23, 43) Source(50, 47) + SourceIndex(0) -8 >Emitted(23, 45) Source(47, 5) + SourceIndex(0) -9 >Emitted(23, 109) Source(50, 47) + SourceIndex(0) -10>Emitted(23, 111) Source(48, 9) + SourceIndex(0) -11>Emitted(23, 126) Source(48, 38) + SourceIndex(0) -12>Emitted(23, 128) Source(48, 9) + SourceIndex(0) -13>Emitted(23, 169) Source(48, 38) + SourceIndex(0) -14>Emitted(23, 171) Source(49, 9) + SourceIndex(0) -15>Emitted(23, 188) Source(49, 44) + SourceIndex(0) -16>Emitted(23, 190) Source(49, 9) + SourceIndex(0) -17>Emitted(23, 235) Source(49, 44) + SourceIndex(0) -18>Emitted(23, 246) Source(51, 22) + SourceIndex(0) -19>Emitted(23, 247) Source(51, 23) + SourceIndex(0) -20>Emitted(23, 250) Source(51, 26) + SourceIndex(0) -21>Emitted(23, 251) Source(51, 27) + SourceIndex(0) -22>Emitted(23, 253) Source(51, 29) + SourceIndex(0) -23>Emitted(23, 254) Source(51, 30) + SourceIndex(0) -24>Emitted(23, 257) Source(51, 33) + SourceIndex(0) -25>Emitted(23, 258) Source(51, 34) + SourceIndex(0) -26>Emitted(23, 260) Source(51, 36) + SourceIndex(0) -27>Emitted(23, 261) Source(51, 37) + SourceIndex(0) -28>Emitted(23, 263) Source(51, 39) + SourceIndex(0) -29>Emitted(23, 265) Source(51, 41) + SourceIndex(0) -30>Emitted(23, 266) Source(51, 42) + SourceIndex(0) +6 >Emitted(23, 28) Source(47, 5) + SourceIndex(0) +7 >Emitted(23, 42) Source(50, 47) + SourceIndex(0) +8 >Emitted(23, 44) Source(47, 5) + SourceIndex(0) +9 >Emitted(23, 108) Source(50, 47) + SourceIndex(0) +10>Emitted(23, 110) Source(48, 9) + SourceIndex(0) +11>Emitted(23, 125) Source(48, 38) + SourceIndex(0) +12>Emitted(23, 127) Source(48, 9) + SourceIndex(0) +13>Emitted(23, 168) Source(48, 38) + SourceIndex(0) +14>Emitted(23, 170) Source(49, 9) + SourceIndex(0) +15>Emitted(23, 187) Source(49, 44) + SourceIndex(0) +16>Emitted(23, 189) Source(49, 9) + SourceIndex(0) +17>Emitted(23, 234) Source(49, 44) + SourceIndex(0) +18>Emitted(23, 240) Source(51, 22) + SourceIndex(0) +19>Emitted(23, 241) Source(51, 23) + SourceIndex(0) +20>Emitted(23, 244) Source(51, 26) + SourceIndex(0) +21>Emitted(23, 245) Source(51, 27) + SourceIndex(0) +22>Emitted(23, 247) Source(51, 29) + SourceIndex(0) +23>Emitted(23, 248) Source(51, 30) + SourceIndex(0) +24>Emitted(23, 251) Source(51, 33) + SourceIndex(0) +25>Emitted(23, 252) Source(51, 34) + SourceIndex(0) +26>Emitted(23, 254) Source(51, 36) + SourceIndex(0) +27>Emitted(23, 255) Source(51, 37) + SourceIndex(0) +28>Emitted(23, 257) Source(51, 39) + SourceIndex(0) +29>Emitted(23, 259) Source(51, 41) + SourceIndex(0) +30>Emitted(23, 260) Source(51, 42) + SourceIndex(0) --- >>> console.log(primaryA); 1 >^^^^ @@ -884,31 +878,31 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(25, 1) Source(53, 1) + SourceIndex(0) 2 >Emitted(25, 2) Source(53, 2) + SourceIndex(0) --- ->>>for (_q = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_r = _q.skills, _s = _r === void 0 ? { primary: "none", secondary: "none" } : _r, _t = _s.primary, primaryA = _t === void 0 ? "primary" : _t, _u = _s.secondary, secondaryA = _u === void 0 ? "secondary" : _u, _q), _q, +>>>for (_q = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _r = _q.skills, _s = _r === void 0 ? { primary: "none", secondary: "none" } : _r, _t = _s.primary, primaryA = _t === void 0 ? "primary" : _t, _u = _s.secondary, secondaryA = _u === void 0 ? "secondary" : _u, _q, 1-> 2 >^^^ 3 > ^ 4 > ^ 5 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -6 > ^^^ -7 > ^^^^^^^^^^^^^^ -8 > ^^ -9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -10> ^^ -11> ^^^^^^^^^^^^^^^ -12> ^^ -13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -14> ^^ -15> ^^^^^^^^^^^^^^^^^ -16> ^^ -17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +6 > ^^ +7 > ^^^^^^^^^^^^^^ +8 > ^^ +9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +10> ^^ +11> ^^^^^^^^^^^^^^^ +12> ^^ +13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +14> ^^ +15> ^^^^^^^^^^^^^^^^^ +16> ^^ +17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1-> > 2 >for @@ -921,41 +915,41 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } } 6 > -7 > skills: { - > primary: primaryA = "primary", - > secondary: secondaryA = "secondary" - > } = { primary: "none", secondary: "none" } -8 > -9 > skills: { - > primary: primaryA = "primary", - > secondary: secondaryA = "secondary" - > } = { primary: "none", secondary: "none" } -10> -11> primary: primaryA = "primary" -12> -13> primary: primaryA = "primary" -14> , - > -15> secondary: secondaryA = "secondary" -16> -17> secondary: secondaryA = "secondary" +7 > skills: { + > primary: primaryA = "primary", + > secondary: secondaryA = "secondary" + > } = { primary: "none", secondary: "none" } +8 > +9 > skills: { + > primary: primaryA = "primary", + > secondary: secondaryA = "secondary" + > } = { primary: "none", secondary: "none" } +10> +11> primary: primaryA = "primary" +12> +13> primary: primaryA = "primary" +14> , + > +15> secondary: secondaryA = "secondary" +16> +17> secondary: secondaryA = "secondary" 1->Emitted(26, 1) Source(54, 1) + SourceIndex(0) 2 >Emitted(26, 4) Source(54, 4) + SourceIndex(0) 3 >Emitted(26, 5) Source(54, 5) + SourceIndex(0) 4 >Emitted(26, 6) Source(54, 6) + SourceIndex(0) 5 >Emitted(26, 84) Source(59, 90) + SourceIndex(0) -6 >Emitted(26, 87) Source(55, 5) + SourceIndex(0) -7 >Emitted(26, 101) Source(58, 47) + SourceIndex(0) -8 >Emitted(26, 103) Source(55, 5) + SourceIndex(0) -9 >Emitted(26, 167) Source(58, 47) + SourceIndex(0) -10>Emitted(26, 169) Source(56, 9) + SourceIndex(0) -11>Emitted(26, 184) Source(56, 38) + SourceIndex(0) -12>Emitted(26, 186) Source(56, 9) + SourceIndex(0) -13>Emitted(26, 227) Source(56, 38) + SourceIndex(0) -14>Emitted(26, 229) Source(57, 9) + SourceIndex(0) -15>Emitted(26, 246) Source(57, 44) + SourceIndex(0) -16>Emitted(26, 248) Source(57, 9) + SourceIndex(0) -17>Emitted(26, 293) Source(57, 44) + SourceIndex(0) +6 >Emitted(26, 86) Source(55, 5) + SourceIndex(0) +7 >Emitted(26, 100) Source(58, 47) + SourceIndex(0) +8 >Emitted(26, 102) Source(55, 5) + SourceIndex(0) +9 >Emitted(26, 166) Source(58, 47) + SourceIndex(0) +10>Emitted(26, 168) Source(56, 9) + SourceIndex(0) +11>Emitted(26, 183) Source(56, 38) + SourceIndex(0) +12>Emitted(26, 185) Source(56, 9) + SourceIndex(0) +13>Emitted(26, 226) Source(56, 38) + SourceIndex(0) +14>Emitted(26, 228) Source(57, 9) + SourceIndex(0) +15>Emitted(26, 245) Source(57, 44) + SourceIndex(0) +16>Emitted(26, 247) Source(57, 9) + SourceIndex(0) +17>Emitted(26, 292) Source(57, 44) + SourceIndex(0) --- >>> i = 0; i < 1; i++) { 1 >^^^^ @@ -1351,14 +1345,14 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(38, 1) Source(72, 1) + SourceIndex(0) 2 >Emitted(38, 2) Source(72, 2) + SourceIndex(0) --- ->>>for (_0 = multiRobot.skills, _1 = _0 === void 0 ? { primary: "none", secondary: "none" } : _0, _2 = _1.primary, primary = _2 === void 0 ? "primary" : _2, _3 = _1.secondary, secondary = _3 === void 0 ? "secondary" : _3, multiRobot, multiRobot, i = 0; i < 1; i++) { +>>>for (_0 = multiRobot.skills, _1 = _0 === void 0 ? { primary: "none", secondary: "none" } : _0, _2 = _1.primary, primary = _2 === void 0 ? "primary" : _2, _3 = _1.secondary, secondary = _3 === void 0 ? "secondary" : _3, multiRobot, i = 0; i < 1; i++) { 1-> 2 >^^^ 3 > ^ @@ -1377,20 +1371,18 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 16> ^^ 17> ^^^^^^^^^^ 18> ^^ -19> ^^^^^^^^^^ -20> ^^ -21> ^ -22> ^^^ -23> ^ -24> ^^ -25> ^ -26> ^^^ -27> ^ -28> ^^ -29> ^ -30> ^^ -31> ^^ -32> ^ +19> ^ +20> ^^^ +21> ^ +22> ^^ +23> ^ +24> ^^^ +25> ^ +26> ^^ +27> ^ +28> ^^ +29> ^^ +30> ^ 1-> > 2 >for @@ -1419,21 +1411,19 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = 17> multiRobot -18> -19> multiRobot -20> , -21> i -22> = -23> 0 -24> ; -25> i -26> < -27> 1 -28> ; -29> i -30> ++ -31> ) -32> { +18> , +19> i +20> = +21> 0 +22> ; +23> i +24> < +25> 1 +26> ; +27> i +28> ++ +29> ) +30> { 1->Emitted(39, 1) Source(73, 1) + SourceIndex(0) 2 >Emitted(39, 4) Source(73, 4) + SourceIndex(0) 3 >Emitted(39, 5) Source(73, 5) + SourceIndex(0) @@ -1451,21 +1441,19 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 15>Emitted(39, 218) Source(76, 32) + SourceIndex(0) 16>Emitted(39, 220) Source(78, 5) + SourceIndex(0) 17>Emitted(39, 230) Source(78, 15) + SourceIndex(0) -18>Emitted(39, 232) Source(78, 5) + SourceIndex(0) -19>Emitted(39, 242) Source(78, 15) + SourceIndex(0) -20>Emitted(39, 244) Source(78, 17) + SourceIndex(0) -21>Emitted(39, 245) Source(78, 18) + SourceIndex(0) -22>Emitted(39, 248) Source(78, 21) + SourceIndex(0) -23>Emitted(39, 249) Source(78, 22) + SourceIndex(0) -24>Emitted(39, 251) Source(78, 24) + SourceIndex(0) -25>Emitted(39, 252) Source(78, 25) + SourceIndex(0) -26>Emitted(39, 255) Source(78, 28) + SourceIndex(0) -27>Emitted(39, 256) Source(78, 29) + SourceIndex(0) -28>Emitted(39, 258) Source(78, 31) + SourceIndex(0) -29>Emitted(39, 259) Source(78, 32) + SourceIndex(0) -30>Emitted(39, 261) Source(78, 34) + SourceIndex(0) -31>Emitted(39, 263) Source(78, 36) + SourceIndex(0) -32>Emitted(39, 264) Source(78, 37) + SourceIndex(0) +18>Emitted(39, 232) Source(78, 17) + SourceIndex(0) +19>Emitted(39, 233) Source(78, 18) + SourceIndex(0) +20>Emitted(39, 236) Source(78, 21) + SourceIndex(0) +21>Emitted(39, 237) Source(78, 22) + SourceIndex(0) +22>Emitted(39, 239) Source(78, 24) + SourceIndex(0) +23>Emitted(39, 240) Source(78, 25) + SourceIndex(0) +24>Emitted(39, 243) Source(78, 28) + SourceIndex(0) +25>Emitted(39, 244) Source(78, 29) + SourceIndex(0) +26>Emitted(39, 246) Source(78, 31) + SourceIndex(0) +27>Emitted(39, 247) Source(78, 32) + SourceIndex(0) +28>Emitted(39, 249) Source(78, 34) + SourceIndex(0) +29>Emitted(39, 251) Source(78, 36) + SourceIndex(0) +30>Emitted(39, 252) Source(78, 37) + SourceIndex(0) --- >>> console.log(primaryA); 1 >^^^^ @@ -1497,44 +1485,44 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(41, 1) Source(80, 1) + SourceIndex(0) 2 >Emitted(41, 2) Source(80, 2) + SourceIndex(0) --- ->>>for (_4 = getMultiRobot(), (_5 = _4.skills, _6 = _5 === void 0 ? { primary: "none", secondary: "none" } : _5, _7 = _6.primary, primary = _7 === void 0 ? "primary" : _7, _8 = _6.secondary, secondary = _8 === void 0 ? "secondary" : _8, _4), _4, i = 0; i < 1; i++) { +>>>for (_4 = getMultiRobot(), _5 = _4.skills, _6 = _5 === void 0 ? { primary: "none", secondary: "none" } : _5, _7 = _6.primary, primary = _7 === void 0 ? "primary" : _7, _8 = _6.secondary, secondary = _8 === void 0 ? "secondary" : _8, _4, i = 0; i < 1; i++) { 1-> 2 >^^^ 3 > ^ 4 > ^ 5 > ^^^^^^^^^^^^^^^^^^^^ -6 > ^^^ -7 > ^^^^^^^^^^^^^^ -8 > ^^ -9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -10> ^^ -11> ^^^^^^^^^^^^^^^ -12> ^^ -13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -14> ^^ -15> ^^^^^^^^^^^^^^^^^ -16> ^^ -17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -18> ^^^^^^^^^^^ -19> ^ -20> ^^^ -21> ^ -22> ^^ -23> ^ -24> ^^^ -25> ^ -26> ^^ -27> ^ -28> ^^ -29> ^^ -30> ^ +6 > ^^ +7 > ^^^^^^^^^^^^^^ +8 > ^^ +9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +10> ^^ +11> ^^^^^^^^^^^^^^^ +12> ^^ +13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +14> ^^ +15> ^^^^^^^^^^^^^^^^^ +16> ^^ +17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +18> ^^^^^^ +19> ^ +20> ^^^ +21> ^ +22> ^^ +23> ^ +24> ^^^ +25> ^ +26> ^^ +27> ^ +28> ^^ +29> ^^ +30> ^ 1-> > 2 >for @@ -1547,69 +1535,69 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = getMultiRobot() 6 > -7 > skills: { - > primary = "primary", - > secondary = "secondary" - > } = { primary: "none", secondary: "none" } -8 > -9 > skills: { - > primary = "primary", - > secondary = "secondary" - > } = { primary: "none", secondary: "none" } -10> -11> primary = "primary" -12> -13> primary = "primary" -14> , - > -15> secondary = "secondary" -16> -17> secondary = "secondary" -18> - > } = { primary: "none", secondary: "none" } - > } = getMultiRobot(), -19> i -20> = -21> 0 -22> ; -23> i -24> < -25> 1 -26> ; -27> i -28> ++ -29> ) -30> { +7 > skills: { + > primary = "primary", + > secondary = "secondary" + > } = { primary: "none", secondary: "none" } +8 > +9 > skills: { + > primary = "primary", + > secondary = "secondary" + > } = { primary: "none", secondary: "none" } +10> +11> primary = "primary" +12> +13> primary = "primary" +14> , + > +15> secondary = "secondary" +16> +17> secondary = "secondary" +18> + > } = { primary: "none", secondary: "none" } + > } = getMultiRobot(), +19> i +20> = +21> 0 +22> ; +23> i +24> < +25> 1 +26> ; +27> i +28> ++ +29> ) +30> { 1->Emitted(42, 1) Source(81, 1) + SourceIndex(0) 2 >Emitted(42, 4) Source(81, 4) + SourceIndex(0) 3 >Emitted(42, 5) Source(81, 5) + SourceIndex(0) 4 >Emitted(42, 6) Source(81, 6) + SourceIndex(0) 5 >Emitted(42, 26) Source(86, 20) + SourceIndex(0) -6 >Emitted(42, 29) Source(82, 5) + SourceIndex(0) -7 >Emitted(42, 43) Source(85, 47) + SourceIndex(0) -8 >Emitted(42, 45) Source(82, 5) + SourceIndex(0) -9 >Emitted(42, 109) Source(85, 47) + SourceIndex(0) -10>Emitted(42, 111) Source(83, 9) + SourceIndex(0) -11>Emitted(42, 126) Source(83, 28) + SourceIndex(0) -12>Emitted(42, 128) Source(83, 9) + SourceIndex(0) -13>Emitted(42, 168) Source(83, 28) + SourceIndex(0) -14>Emitted(42, 170) Source(84, 9) + SourceIndex(0) -15>Emitted(42, 187) Source(84, 32) + SourceIndex(0) -16>Emitted(42, 189) Source(84, 9) + SourceIndex(0) -17>Emitted(42, 233) Source(84, 32) + SourceIndex(0) -18>Emitted(42, 244) Source(86, 22) + SourceIndex(0) -19>Emitted(42, 245) Source(86, 23) + SourceIndex(0) -20>Emitted(42, 248) Source(86, 26) + SourceIndex(0) -21>Emitted(42, 249) Source(86, 27) + SourceIndex(0) -22>Emitted(42, 251) Source(86, 29) + SourceIndex(0) -23>Emitted(42, 252) Source(86, 30) + SourceIndex(0) -24>Emitted(42, 255) Source(86, 33) + SourceIndex(0) -25>Emitted(42, 256) Source(86, 34) + SourceIndex(0) -26>Emitted(42, 258) Source(86, 36) + SourceIndex(0) -27>Emitted(42, 259) Source(86, 37) + SourceIndex(0) -28>Emitted(42, 261) Source(86, 39) + SourceIndex(0) -29>Emitted(42, 263) Source(86, 41) + SourceIndex(0) -30>Emitted(42, 264) Source(86, 42) + SourceIndex(0) +6 >Emitted(42, 28) Source(82, 5) + SourceIndex(0) +7 >Emitted(42, 42) Source(85, 47) + SourceIndex(0) +8 >Emitted(42, 44) Source(82, 5) + SourceIndex(0) +9 >Emitted(42, 108) Source(85, 47) + SourceIndex(0) +10>Emitted(42, 110) Source(83, 9) + SourceIndex(0) +11>Emitted(42, 125) Source(83, 28) + SourceIndex(0) +12>Emitted(42, 127) Source(83, 9) + SourceIndex(0) +13>Emitted(42, 167) Source(83, 28) + SourceIndex(0) +14>Emitted(42, 169) Source(84, 9) + SourceIndex(0) +15>Emitted(42, 186) Source(84, 32) + SourceIndex(0) +16>Emitted(42, 188) Source(84, 9) + SourceIndex(0) +17>Emitted(42, 232) Source(84, 32) + SourceIndex(0) +18>Emitted(42, 238) Source(86, 22) + SourceIndex(0) +19>Emitted(42, 239) Source(86, 23) + SourceIndex(0) +20>Emitted(42, 242) Source(86, 26) + SourceIndex(0) +21>Emitted(42, 243) Source(86, 27) + SourceIndex(0) +22>Emitted(42, 245) Source(86, 29) + SourceIndex(0) +23>Emitted(42, 246) Source(86, 30) + SourceIndex(0) +24>Emitted(42, 249) Source(86, 33) + SourceIndex(0) +25>Emitted(42, 250) Source(86, 34) + SourceIndex(0) +26>Emitted(42, 252) Source(86, 36) + SourceIndex(0) +27>Emitted(42, 253) Source(86, 37) + SourceIndex(0) +28>Emitted(42, 255) Source(86, 39) + SourceIndex(0) +29>Emitted(42, 257) Source(86, 41) + SourceIndex(0) +30>Emitted(42, 258) Source(86, 42) + SourceIndex(0) --- >>> console.log(primaryA); 1 >^^^^ @@ -1641,31 +1629,31 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(44, 1) Source(88, 1) + SourceIndex(0) 2 >Emitted(44, 2) Source(88, 2) + SourceIndex(0) --- ->>>for (_9 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_10 = _9.skills, _11 = _10 === void 0 ? { primary: "none", secondary: "none" } : _10, _12 = _11.primary, primary = _12 === void 0 ? "primary" : _12, _13 = _11.secondary, secondary = _13 === void 0 ? "secondary" : _13, _9), _9, +>>>for (_9 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _10 = _9.skills, _11 = _10 === void 0 ? { primary: "none", secondary: "none" } : _10, _12 = _11.primary, primary = _12 === void 0 ? "primary" : _12, _13 = _11.secondary, secondary = _13 === void 0 ? "secondary" : _13, _9, 1-> 2 >^^^ 3 > ^ 4 > ^ 5 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -6 > ^^^ -7 > ^^^^^^^^^^^^^^^ -8 > ^^ -9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -10> ^^ -11> ^^^^^^^^^^^^^^^^^ -12> ^^ -13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -14> ^^ -15> ^^^^^^^^^^^^^^^^^^^ -16> ^^ -17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +6 > ^^ +7 > ^^^^^^^^^^^^^^^ +8 > ^^ +9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +10> ^^ +11> ^^^^^^^^^^^^^^^^^ +12> ^^ +13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +14> ^^ +15> ^^^^^^^^^^^^^^^^^^^ +16> ^^ +17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1-> > 2 >for @@ -1678,41 +1666,41 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } } 6 > -7 > skills: { - > primary = "primary", - > secondary = "secondary" - > } = { primary: "none", secondary: "none" } -8 > -9 > skills: { - > primary = "primary", - > secondary = "secondary" - > } = { primary: "none", secondary: "none" } -10> -11> primary = "primary" -12> -13> primary = "primary" -14> , - > -15> secondary = "secondary" -16> -17> secondary = "secondary" +7 > skills: { + > primary = "primary", + > secondary = "secondary" + > } = { primary: "none", secondary: "none" } +8 > +9 > skills: { + > primary = "primary", + > secondary = "secondary" + > } = { primary: "none", secondary: "none" } +10> +11> primary = "primary" +12> +13> primary = "primary" +14> , + > +15> secondary = "secondary" +16> +17> secondary = "secondary" 1->Emitted(45, 1) Source(89, 1) + SourceIndex(0) 2 >Emitted(45, 4) Source(89, 4) + SourceIndex(0) 3 >Emitted(45, 5) Source(89, 5) + SourceIndex(0) 4 >Emitted(45, 6) Source(89, 6) + SourceIndex(0) 5 >Emitted(45, 84) Source(94, 90) + SourceIndex(0) -6 >Emitted(45, 87) Source(90, 5) + SourceIndex(0) -7 >Emitted(45, 102) Source(93, 47) + SourceIndex(0) -8 >Emitted(45, 104) Source(90, 5) + SourceIndex(0) -9 >Emitted(45, 171) Source(93, 47) + SourceIndex(0) -10>Emitted(45, 173) Source(91, 9) + SourceIndex(0) -11>Emitted(45, 190) Source(91, 28) + SourceIndex(0) -12>Emitted(45, 192) Source(91, 9) + SourceIndex(0) -13>Emitted(45, 234) Source(91, 28) + SourceIndex(0) -14>Emitted(45, 236) Source(92, 9) + SourceIndex(0) -15>Emitted(45, 255) Source(92, 32) + SourceIndex(0) -16>Emitted(45, 257) Source(92, 9) + SourceIndex(0) -17>Emitted(45, 303) Source(92, 32) + SourceIndex(0) +6 >Emitted(45, 86) Source(90, 5) + SourceIndex(0) +7 >Emitted(45, 101) Source(93, 47) + SourceIndex(0) +8 >Emitted(45, 103) Source(90, 5) + SourceIndex(0) +9 >Emitted(45, 170) Source(93, 47) + SourceIndex(0) +10>Emitted(45, 172) Source(91, 9) + SourceIndex(0) +11>Emitted(45, 189) Source(91, 28) + SourceIndex(0) +12>Emitted(45, 191) Source(91, 9) + SourceIndex(0) +13>Emitted(45, 233) Source(91, 28) + SourceIndex(0) +14>Emitted(45, 235) Source(92, 9) + SourceIndex(0) +15>Emitted(45, 254) Source(92, 32) + SourceIndex(0) +16>Emitted(45, 256) Source(92, 9) + SourceIndex(0) +17>Emitted(45, 302) Source(92, 32) + SourceIndex(0) --- >>> i = 0; i < 1; i++) { 1 >^^^^ @@ -2145,14 +2133,14 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(57, 1) Source(108, 1) + SourceIndex(0) 2 >Emitted(57, 2) Source(108, 2) + SourceIndex(0) --- ->>>for (_22 = multiRobot.name, nameA = _22 === void 0 ? "noName" : _22, _23 = multiRobot.skills, _24 = _23 === void 0 ? { primary: "none", secondary: "none" } : _23, _25 = _24.primary, primaryA = _25 === void 0 ? "primary" : _25, _26 = _24.secondary, secondaryA = _26 === void 0 ? "secondary" : _26, multiRobot, multiRobot, i = 0; i < 1; i++) { +>>>for (_22 = multiRobot.name, nameA = _22 === void 0 ? "noName" : _22, _23 = multiRobot.skills, _24 = _23 === void 0 ? { primary: "none", secondary: "none" } : _23, _25 = _24.primary, primaryA = _25 === void 0 ? "primary" : _25, _26 = _24.secondary, secondaryA = _26 === void 0 ? "secondary" : _26, multiRobot, i = 0; i < 1; i++) { 1-> 2 >^^^ 3 > ^ @@ -2175,20 +2163,18 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 20> ^^ 21> ^^^^^^^^^^ 22> ^^ -23> ^^^^^^^^^^ -24> ^^ -25> ^ -26> ^^^ -27> ^ -28> ^^ -29> ^ -30> ^^^ -31> ^ -32> ^^ -33> ^ -34> ^^ -35> ^^ -36> ^ +23> ^ +24> ^^^ +25> ^ +26> ^^ +27> ^ +28> ^^^ +29> ^ +30> ^^ +31> ^ +32> ^^ +33> ^^ +34> ^ 1-> > 2 >for @@ -2222,21 +2208,19 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = 21> multiRobot -22> -23> multiRobot -24> , -25> i -26> = -27> 0 -28> ; -29> i -30> < -31> 1 -32> ; -33> i -34> ++ -35> ) -36> { +22> , +23> i +24> = +25> 0 +26> ; +27> i +28> < +29> 1 +30> ; +31> i +32> ++ +33> ) +34> { 1->Emitted(58, 1) Source(109, 1) + SourceIndex(0) 2 >Emitted(58, 4) Source(109, 4) + SourceIndex(0) 3 >Emitted(58, 5) Source(109, 5) + SourceIndex(0) @@ -2258,21 +2242,19 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 19>Emitted(58, 296) Source(113, 44) + SourceIndex(0) 20>Emitted(58, 298) Source(115, 5) + SourceIndex(0) 21>Emitted(58, 308) Source(115, 15) + SourceIndex(0) -22>Emitted(58, 310) Source(115, 5) + SourceIndex(0) -23>Emitted(58, 320) Source(115, 15) + SourceIndex(0) -24>Emitted(58, 322) Source(115, 17) + SourceIndex(0) -25>Emitted(58, 323) Source(115, 18) + SourceIndex(0) -26>Emitted(58, 326) Source(115, 21) + SourceIndex(0) -27>Emitted(58, 327) Source(115, 22) + SourceIndex(0) -28>Emitted(58, 329) Source(115, 24) + SourceIndex(0) -29>Emitted(58, 330) Source(115, 25) + SourceIndex(0) -30>Emitted(58, 333) Source(115, 28) + SourceIndex(0) -31>Emitted(58, 334) Source(115, 29) + SourceIndex(0) -32>Emitted(58, 336) Source(115, 31) + SourceIndex(0) -33>Emitted(58, 337) Source(115, 32) + SourceIndex(0) -34>Emitted(58, 339) Source(115, 34) + SourceIndex(0) -35>Emitted(58, 341) Source(115, 36) + SourceIndex(0) -36>Emitted(58, 342) Source(115, 37) + SourceIndex(0) +22>Emitted(58, 310) Source(115, 17) + SourceIndex(0) +23>Emitted(58, 311) Source(115, 18) + SourceIndex(0) +24>Emitted(58, 314) Source(115, 21) + SourceIndex(0) +25>Emitted(58, 315) Source(115, 22) + SourceIndex(0) +26>Emitted(58, 317) Source(115, 24) + SourceIndex(0) +27>Emitted(58, 318) Source(115, 25) + SourceIndex(0) +28>Emitted(58, 321) Source(115, 28) + SourceIndex(0) +29>Emitted(58, 322) Source(115, 29) + SourceIndex(0) +30>Emitted(58, 324) Source(115, 31) + SourceIndex(0) +31>Emitted(58, 325) Source(115, 32) + SourceIndex(0) +32>Emitted(58, 327) Source(115, 34) + SourceIndex(0) +33>Emitted(58, 329) Source(115, 36) + SourceIndex(0) +34>Emitted(58, 330) Source(115, 37) + SourceIndex(0) --- >>> console.log(primaryA); 1 >^^^^ @@ -2304,48 +2286,48 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(60, 1) Source(117, 1) + SourceIndex(0) 2 >Emitted(60, 2) Source(117, 2) + SourceIndex(0) --- ->>>for (_27 = getMultiRobot(), (_28 = _27.name, nameA = _28 === void 0 ? "noName" : _28, _29 = _27.skills, _30 = _29 === void 0 ? { primary: "none", secondary: "none" } : _29, _31 = _30.primary, primaryA = _31 === void 0 ? "primary" : _31, _32 = _30.secondary, secondaryA = _32 === void 0 ? "secondary" : _32, _27), _27, i = 0; i < 1; i++) { +>>>for (_27 = getMultiRobot(), _28 = _27.name, nameA = _28 === void 0 ? "noName" : _28, _29 = _27.skills, _30 = _29 === void 0 ? { primary: "none", secondary: "none" } : _29, _31 = _30.primary, primaryA = _31 === void 0 ? "primary" : _31, _32 = _30.secondary, secondaryA = _32 === void 0 ? "secondary" : _32, _27, i = 0; i < 1; i++) { 1-> 2 >^^^ 3 > ^ 4 > ^ 5 > ^^^^^^^^^^^^^^^^^^^^^ -6 > ^^^ -7 > ^^^^^^^^^^^^^^ -8 > ^^ -9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -10> ^^ -11> ^^^^^^^^^^^^^^^^ -12> ^^ -13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -14> ^^ -15> ^^^^^^^^^^^^^^^^^ -16> ^^ -17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -18> ^^ -19> ^^^^^^^^^^^^^^^^^^^ -20> ^^ -21> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -22> ^^^^^^^^^^^^^ -23> ^ -24> ^^^ -25> ^ -26> ^^ -27> ^ -28> ^^^ -29> ^ -30> ^^ -31> ^ -32> ^^ -33> ^^ -34> ^ +6 > ^^ +7 > ^^^^^^^^^^^^^^ +8 > ^^ +9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +10> ^^ +11> ^^^^^^^^^^^^^^^^ +12> ^^ +13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +14> ^^ +15> ^^^^^^^^^^^^^^^^^ +16> ^^ +17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +18> ^^ +19> ^^^^^^^^^^^^^^^^^^^ +20> ^^ +21> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +22> ^^^^^^^ +23> ^ +24> ^^^ +25> ^ +26> ^^ +27> ^ +28> ^^^ +29> ^ +30> ^^ +31> ^ +32> ^^ +33> ^^ +34> ^ 1-> > 2 >for @@ -2359,78 +2341,78 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = getMultiRobot() 6 > -7 > name: nameA = "noName" -8 > -9 > name: nameA = "noName" -10> , - > -11> skills: { - > primary: primaryA = "primary", - > secondary: secondaryA = "secondary" - > } = { primary: "none", secondary: "none" } -12> -13> skills: { - > primary: primaryA = "primary", - > secondary: secondaryA = "secondary" - > } = { primary: "none", secondary: "none" } -14> -15> primary: primaryA = "primary" -16> -17> primary: primaryA = "primary" -18> , - > -19> secondary: secondaryA = "secondary" -20> -21> secondary: secondaryA = "secondary" -22> - > } = { primary: "none", secondary: "none" } - > } = getMultiRobot(), -23> i -24> = -25> 0 -26> ; -27> i -28> < -29> 1 -30> ; -31> i -32> ++ -33> ) -34> { +7 > name: nameA = "noName" +8 > +9 > name: nameA = "noName" +10> , + > +11> skills: { + > primary: primaryA = "primary", + > secondary: secondaryA = "secondary" + > } = { primary: "none", secondary: "none" } +12> +13> skills: { + > primary: primaryA = "primary", + > secondary: secondaryA = "secondary" + > } = { primary: "none", secondary: "none" } +14> +15> primary: primaryA = "primary" +16> +17> primary: primaryA = "primary" +18> , + > +19> secondary: secondaryA = "secondary" +20> +21> secondary: secondaryA = "secondary" +22> + > } = { primary: "none", secondary: "none" } + > } = getMultiRobot(), +23> i +24> = +25> 0 +26> ; +27> i +28> < +29> 1 +30> ; +31> i +32> ++ +33> ) +34> { 1->Emitted(61, 1) Source(118, 1) + SourceIndex(0) 2 >Emitted(61, 4) Source(118, 4) + SourceIndex(0) 3 >Emitted(61, 5) Source(118, 5) + SourceIndex(0) 4 >Emitted(61, 6) Source(118, 6) + SourceIndex(0) 5 >Emitted(61, 27) Source(124, 20) + SourceIndex(0) -6 >Emitted(61, 30) Source(119, 5) + SourceIndex(0) -7 >Emitted(61, 44) Source(119, 27) + SourceIndex(0) -8 >Emitted(61, 46) Source(119, 5) + SourceIndex(0) -9 >Emitted(61, 85) Source(119, 27) + SourceIndex(0) -10>Emitted(61, 87) Source(120, 5) + SourceIndex(0) -11>Emitted(61, 103) Source(123, 47) + SourceIndex(0) -12>Emitted(61, 105) Source(120, 5) + SourceIndex(0) -13>Emitted(61, 172) Source(123, 47) + SourceIndex(0) -14>Emitted(61, 174) Source(121, 9) + SourceIndex(0) -15>Emitted(61, 191) Source(121, 38) + SourceIndex(0) -16>Emitted(61, 193) Source(121, 9) + SourceIndex(0) -17>Emitted(61, 236) Source(121, 38) + SourceIndex(0) -18>Emitted(61, 238) Source(122, 9) + SourceIndex(0) -19>Emitted(61, 257) Source(122, 44) + SourceIndex(0) -20>Emitted(61, 259) Source(122, 9) + SourceIndex(0) -21>Emitted(61, 306) Source(122, 44) + SourceIndex(0) -22>Emitted(61, 319) Source(124, 22) + SourceIndex(0) -23>Emitted(61, 320) Source(124, 23) + SourceIndex(0) -24>Emitted(61, 323) Source(124, 26) + SourceIndex(0) -25>Emitted(61, 324) Source(124, 27) + SourceIndex(0) -26>Emitted(61, 326) Source(124, 29) + SourceIndex(0) -27>Emitted(61, 327) Source(124, 30) + SourceIndex(0) -28>Emitted(61, 330) Source(124, 33) + SourceIndex(0) -29>Emitted(61, 331) Source(124, 34) + SourceIndex(0) -30>Emitted(61, 333) Source(124, 36) + SourceIndex(0) -31>Emitted(61, 334) Source(124, 37) + SourceIndex(0) -32>Emitted(61, 336) Source(124, 39) + SourceIndex(0) -33>Emitted(61, 338) Source(124, 41) + SourceIndex(0) -34>Emitted(61, 339) Source(124, 42) + SourceIndex(0) +6 >Emitted(61, 29) Source(119, 5) + SourceIndex(0) +7 >Emitted(61, 43) Source(119, 27) + SourceIndex(0) +8 >Emitted(61, 45) Source(119, 5) + SourceIndex(0) +9 >Emitted(61, 84) Source(119, 27) + SourceIndex(0) +10>Emitted(61, 86) Source(120, 5) + SourceIndex(0) +11>Emitted(61, 102) Source(123, 47) + SourceIndex(0) +12>Emitted(61, 104) Source(120, 5) + SourceIndex(0) +13>Emitted(61, 171) Source(123, 47) + SourceIndex(0) +14>Emitted(61, 173) Source(121, 9) + SourceIndex(0) +15>Emitted(61, 190) Source(121, 38) + SourceIndex(0) +16>Emitted(61, 192) Source(121, 9) + SourceIndex(0) +17>Emitted(61, 235) Source(121, 38) + SourceIndex(0) +18>Emitted(61, 237) Source(122, 9) + SourceIndex(0) +19>Emitted(61, 256) Source(122, 44) + SourceIndex(0) +20>Emitted(61, 258) Source(122, 9) + SourceIndex(0) +21>Emitted(61, 305) Source(122, 44) + SourceIndex(0) +22>Emitted(61, 312) Source(124, 22) + SourceIndex(0) +23>Emitted(61, 313) Source(124, 23) + SourceIndex(0) +24>Emitted(61, 316) Source(124, 26) + SourceIndex(0) +25>Emitted(61, 317) Source(124, 27) + SourceIndex(0) +26>Emitted(61, 319) Source(124, 29) + SourceIndex(0) +27>Emitted(61, 320) Source(124, 30) + SourceIndex(0) +28>Emitted(61, 323) Source(124, 33) + SourceIndex(0) +29>Emitted(61, 324) Source(124, 34) + SourceIndex(0) +30>Emitted(61, 326) Source(124, 36) + SourceIndex(0) +31>Emitted(61, 327) Source(124, 37) + SourceIndex(0) +32>Emitted(61, 329) Source(124, 39) + SourceIndex(0) +33>Emitted(61, 331) Source(124, 41) + SourceIndex(0) +34>Emitted(61, 332) Source(124, 42) + SourceIndex(0) --- >>> console.log(primaryA); 1 >^^^^ @@ -2462,35 +2444,35 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(63, 1) Source(126, 1) + SourceIndex(0) 2 >Emitted(63, 2) Source(126, 2) + SourceIndex(0) --- ->>>for (_33 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_34 = _33.name, nameA = _34 === void 0 ? "noName" : _34, _35 = _33.skills, _36 = _35 === void 0 ? { primary: "none", secondary: "none" } : _35, _37 = _36.primary, primaryA = _37 === void 0 ? "primary" : _37, _38 = _36.secondary, secondaryA = _38 === void 0 ? "secondary" : _38, _33), _33, +>>>for (_33 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _34 = _33.name, nameA = _34 === void 0 ? "noName" : _34, _35 = _33.skills, _36 = _35 === void 0 ? { primary: "none", secondary: "none" } : _35, _37 = _36.primary, primaryA = _37 === void 0 ? "primary" : _37, _38 = _36.secondary, secondaryA = _38 === void 0 ? "secondary" : _38, _33, 1-> 2 >^^^ 3 > ^ 4 > ^ 5 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -6 > ^^^ -7 > ^^^^^^^^^^^^^^ -8 > ^^ -9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -10> ^^ -11> ^^^^^^^^^^^^^^^^ -12> ^^ -13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -14> ^^ -15> ^^^^^^^^^^^^^^^^^ -16> ^^ -17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -18> ^^ -19> ^^^^^^^^^^^^^^^^^^^ -20> ^^ -21> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +6 > ^^ +7 > ^^^^^^^^^^^^^^ +8 > ^^ +9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +10> ^^ +11> ^^^^^^^^^^^^^^^^ +12> ^^ +13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +14> ^^ +15> ^^^^^^^^^^^^^^^^^ +16> ^^ +17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +18> ^^ +19> ^^^^^^^^^^^^^^^^^^^ +20> ^^ +21> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1-> > 2 >for @@ -2504,50 +2486,50 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } } 6 > -7 > name: nameA = "noName" -8 > -9 > name: nameA = "noName" -10> , - > -11> skills: { - > primary: primaryA = "primary", - > secondary: secondaryA = "secondary" - > } = { primary: "none", secondary: "none" } -12> -13> skills: { - > primary: primaryA = "primary", - > secondary: secondaryA = "secondary" - > } = { primary: "none", secondary: "none" } -14> -15> primary: primaryA = "primary" -16> -17> primary: primaryA = "primary" -18> , - > -19> secondary: secondaryA = "secondary" -20> -21> secondary: secondaryA = "secondary" +7 > name: nameA = "noName" +8 > +9 > name: nameA = "noName" +10> , + > +11> skills: { + > primary: primaryA = "primary", + > secondary: secondaryA = "secondary" + > } = { primary: "none", secondary: "none" } +12> +13> skills: { + > primary: primaryA = "primary", + > secondary: secondaryA = "secondary" + > } = { primary: "none", secondary: "none" } +14> +15> primary: primaryA = "primary" +16> +17> primary: primaryA = "primary" +18> , + > +19> secondary: secondaryA = "secondary" +20> +21> secondary: secondaryA = "secondary" 1->Emitted(64, 1) Source(127, 1) + SourceIndex(0) 2 >Emitted(64, 4) Source(127, 4) + SourceIndex(0) 3 >Emitted(64, 5) Source(127, 5) + SourceIndex(0) 4 >Emitted(64, 6) Source(127, 6) + SourceIndex(0) 5 >Emitted(64, 85) Source(133, 90) + SourceIndex(0) -6 >Emitted(64, 88) Source(128, 5) + SourceIndex(0) -7 >Emitted(64, 102) Source(128, 27) + SourceIndex(0) -8 >Emitted(64, 104) Source(128, 5) + SourceIndex(0) -9 >Emitted(64, 143) Source(128, 27) + SourceIndex(0) -10>Emitted(64, 145) Source(129, 5) + SourceIndex(0) -11>Emitted(64, 161) Source(132, 47) + SourceIndex(0) -12>Emitted(64, 163) Source(129, 5) + SourceIndex(0) -13>Emitted(64, 230) Source(132, 47) + SourceIndex(0) -14>Emitted(64, 232) Source(130, 9) + SourceIndex(0) -15>Emitted(64, 249) Source(130, 38) + SourceIndex(0) -16>Emitted(64, 251) Source(130, 9) + SourceIndex(0) -17>Emitted(64, 294) Source(130, 38) + SourceIndex(0) -18>Emitted(64, 296) Source(131, 9) + SourceIndex(0) -19>Emitted(64, 315) Source(131, 44) + SourceIndex(0) -20>Emitted(64, 317) Source(131, 9) + SourceIndex(0) -21>Emitted(64, 364) Source(131, 44) + SourceIndex(0) +6 >Emitted(64, 87) Source(128, 5) + SourceIndex(0) +7 >Emitted(64, 101) Source(128, 27) + SourceIndex(0) +8 >Emitted(64, 103) Source(128, 5) + SourceIndex(0) +9 >Emitted(64, 142) Source(128, 27) + SourceIndex(0) +10>Emitted(64, 144) Source(129, 5) + SourceIndex(0) +11>Emitted(64, 160) Source(132, 47) + SourceIndex(0) +12>Emitted(64, 162) Source(129, 5) + SourceIndex(0) +13>Emitted(64, 229) Source(132, 47) + SourceIndex(0) +14>Emitted(64, 231) Source(130, 9) + SourceIndex(0) +15>Emitted(64, 248) Source(130, 38) + SourceIndex(0) +16>Emitted(64, 250) Source(130, 9) + SourceIndex(0) +17>Emitted(64, 293) Source(130, 38) + SourceIndex(0) +18>Emitted(64, 295) Source(131, 9) + SourceIndex(0) +19>Emitted(64, 314) Source(131, 44) + SourceIndex(0) +20>Emitted(64, 316) Source(131, 9) + SourceIndex(0) +21>Emitted(64, 363) Source(131, 44) + SourceIndex(0) --- >>> i = 0; i < 1; i++) { 1 >^^^^ @@ -2979,14 +2961,14 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(76, 1) Source(146, 1) + SourceIndex(0) 2 >Emitted(76, 2) Source(146, 2) + SourceIndex(0) --- ->>>for (_47 = multiRobot.name, name = _47 === void 0 ? "noName" : _47, _48 = multiRobot.skills, _49 = _48 === void 0 ? { primary: "none", secondary: "none" } : _48, _50 = _49.primary, primary = _50 === void 0 ? "primary" : _50, _51 = _49.secondary, secondary = _51 === void 0 ? "secondary" : _51, multiRobot, multiRobot, i = 0; i < 1; i++) { +>>>for (_47 = multiRobot.name, name = _47 === void 0 ? "noName" : _47, _48 = multiRobot.skills, _49 = _48 === void 0 ? { primary: "none", secondary: "none" } : _48, _50 = _49.primary, primary = _50 === void 0 ? "primary" : _50, _51 = _49.secondary, secondary = _51 === void 0 ? "secondary" : _51, multiRobot, i = 0; i < 1; i++) { 1-> 2 >^^^ 3 > ^ @@ -3009,20 +2991,18 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 20> ^^ 21> ^^^^^^^^^^ 22> ^^ -23> ^^^^^^^^^^ -24> ^^ -25> ^ -26> ^^^ -27> ^ -28> ^^ -29> ^ -30> ^^^ -31> ^ -32> ^^ -33> ^ -34> ^^ -35> ^^ -36> ^ +23> ^ +24> ^^^ +25> ^ +26> ^^ +27> ^ +28> ^^^ +29> ^ +30> ^^ +31> ^ +32> ^^ +33> ^^ +34> ^ 1-> > 2 >for @@ -3056,21 +3036,19 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = 21> multiRobot -22> -23> multiRobot -24> , -25> i -26> = -27> 0 -28> ; -29> i -30> < -31> 1 -32> ; -33> i -34> ++ -35> ) -36> { +22> , +23> i +24> = +25> 0 +26> ; +27> i +28> < +29> 1 +30> ; +31> i +32> ++ +33> ) +34> { 1->Emitted(77, 1) Source(147, 1) + SourceIndex(0) 2 >Emitted(77, 4) Source(147, 4) + SourceIndex(0) 3 >Emitted(77, 5) Source(147, 5) + SourceIndex(0) @@ -3092,21 +3070,19 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 19>Emitted(77, 293) Source(151, 32) + SourceIndex(0) 20>Emitted(77, 295) Source(153, 5) + SourceIndex(0) 21>Emitted(77, 305) Source(153, 15) + SourceIndex(0) -22>Emitted(77, 307) Source(153, 5) + SourceIndex(0) -23>Emitted(77, 317) Source(153, 15) + SourceIndex(0) -24>Emitted(77, 319) Source(153, 17) + SourceIndex(0) -25>Emitted(77, 320) Source(153, 18) + SourceIndex(0) -26>Emitted(77, 323) Source(153, 21) + SourceIndex(0) -27>Emitted(77, 324) Source(153, 22) + SourceIndex(0) -28>Emitted(77, 326) Source(153, 24) + SourceIndex(0) -29>Emitted(77, 327) Source(153, 25) + SourceIndex(0) -30>Emitted(77, 330) Source(153, 28) + SourceIndex(0) -31>Emitted(77, 331) Source(153, 29) + SourceIndex(0) -32>Emitted(77, 333) Source(153, 31) + SourceIndex(0) -33>Emitted(77, 334) Source(153, 32) + SourceIndex(0) -34>Emitted(77, 336) Source(153, 34) + SourceIndex(0) -35>Emitted(77, 338) Source(153, 36) + SourceIndex(0) -36>Emitted(77, 339) Source(153, 37) + SourceIndex(0) +22>Emitted(77, 307) Source(153, 17) + SourceIndex(0) +23>Emitted(77, 308) Source(153, 18) + SourceIndex(0) +24>Emitted(77, 311) Source(153, 21) + SourceIndex(0) +25>Emitted(77, 312) Source(153, 22) + SourceIndex(0) +26>Emitted(77, 314) Source(153, 24) + SourceIndex(0) +27>Emitted(77, 315) Source(153, 25) + SourceIndex(0) +28>Emitted(77, 318) Source(153, 28) + SourceIndex(0) +29>Emitted(77, 319) Source(153, 29) + SourceIndex(0) +30>Emitted(77, 321) Source(153, 31) + SourceIndex(0) +31>Emitted(77, 322) Source(153, 32) + SourceIndex(0) +32>Emitted(77, 324) Source(153, 34) + SourceIndex(0) +33>Emitted(77, 326) Source(153, 36) + SourceIndex(0) +34>Emitted(77, 327) Source(153, 37) + SourceIndex(0) --- >>> console.log(primaryA); 1 >^^^^ @@ -3138,48 +3114,48 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(79, 1) Source(155, 1) + SourceIndex(0) 2 >Emitted(79, 2) Source(155, 2) + SourceIndex(0) --- ->>>for (_52 = getMultiRobot(), (_53 = _52.name, name = _53 === void 0 ? "noName" : _53, _54 = _52.skills, _55 = _54 === void 0 ? { primary: "none", secondary: "none" } : _54, _56 = _55.primary, primary = _56 === void 0 ? "primary" : _56, _57 = _55.secondary, secondary = _57 === void 0 ? "secondary" : _57, _52), _52, i = 0; i < 1; i++) { +>>>for (_52 = getMultiRobot(), _53 = _52.name, name = _53 === void 0 ? "noName" : _53, _54 = _52.skills, _55 = _54 === void 0 ? { primary: "none", secondary: "none" } : _54, _56 = _55.primary, primary = _56 === void 0 ? "primary" : _56, _57 = _55.secondary, secondary = _57 === void 0 ? "secondary" : _57, _52, i = 0; i < 1; i++) { 1-> 2 >^^^ 3 > ^ 4 > ^ 5 > ^^^^^^^^^^^^^^^^^^^^^ -6 > ^^^ -7 > ^^^^^^^^^^^^^^ -8 > ^^ -9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -10> ^^ -11> ^^^^^^^^^^^^^^^^ -12> ^^ -13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -14> ^^ -15> ^^^^^^^^^^^^^^^^^ -16> ^^ -17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -18> ^^ -19> ^^^^^^^^^^^^^^^^^^^ -20> ^^ -21> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -22> ^^^^^^^^^^^^^ -23> ^ -24> ^^^ -25> ^ -26> ^^ -27> ^ -28> ^^^ -29> ^ -30> ^^ -31> ^ -32> ^^ -33> ^^ -34> ^ +6 > ^^ +7 > ^^^^^^^^^^^^^^ +8 > ^^ +9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +10> ^^ +11> ^^^^^^^^^^^^^^^^ +12> ^^ +13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +14> ^^ +15> ^^^^^^^^^^^^^^^^^ +16> ^^ +17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +18> ^^ +19> ^^^^^^^^^^^^^^^^^^^ +20> ^^ +21> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +22> ^^^^^^^ +23> ^ +24> ^^^ +25> ^ +26> ^^ +27> ^ +28> ^^^ +29> ^ +30> ^^ +31> ^ +32> ^^ +33> ^^ +34> ^ 1-> > 2 >for @@ -3193,78 +3169,78 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = getMultiRobot() 6 > -7 > name = "noName" -8 > -9 > name = "noName" -10> , - > -11> skills: { - > primary = "primary", - > secondary = "secondary" - > } = { primary: "none", secondary: "none" } -12> -13> skills: { - > primary = "primary", - > secondary = "secondary" - > } = { primary: "none", secondary: "none" } -14> -15> primary = "primary" -16> -17> primary = "primary" -18> , - > -19> secondary = "secondary" -20> -21> secondary = "secondary" -22> - > } = { primary: "none", secondary: "none" } - > } = getMultiRobot(), -23> i -24> = -25> 0 -26> ; -27> i -28> < -29> 1 -30> ; -31> i -32> ++ -33> ) -34> { +7 > name = "noName" +8 > +9 > name = "noName" +10> , + > +11> skills: { + > primary = "primary", + > secondary = "secondary" + > } = { primary: "none", secondary: "none" } +12> +13> skills: { + > primary = "primary", + > secondary = "secondary" + > } = { primary: "none", secondary: "none" } +14> +15> primary = "primary" +16> +17> primary = "primary" +18> , + > +19> secondary = "secondary" +20> +21> secondary = "secondary" +22> + > } = { primary: "none", secondary: "none" } + > } = getMultiRobot(), +23> i +24> = +25> 0 +26> ; +27> i +28> < +29> 1 +30> ; +31> i +32> ++ +33> ) +34> { 1->Emitted(80, 1) Source(156, 1) + SourceIndex(0) 2 >Emitted(80, 4) Source(156, 4) + SourceIndex(0) 3 >Emitted(80, 5) Source(156, 5) + SourceIndex(0) 4 >Emitted(80, 6) Source(156, 6) + SourceIndex(0) 5 >Emitted(80, 27) Source(162, 20) + SourceIndex(0) -6 >Emitted(80, 30) Source(157, 5) + SourceIndex(0) -7 >Emitted(80, 44) Source(157, 20) + SourceIndex(0) -8 >Emitted(80, 46) Source(157, 5) + SourceIndex(0) -9 >Emitted(80, 84) Source(157, 20) + SourceIndex(0) -10>Emitted(80, 86) Source(158, 5) + SourceIndex(0) -11>Emitted(80, 102) Source(161, 47) + SourceIndex(0) -12>Emitted(80, 104) Source(158, 5) + SourceIndex(0) -13>Emitted(80, 171) Source(161, 47) + SourceIndex(0) -14>Emitted(80, 173) Source(159, 9) + SourceIndex(0) -15>Emitted(80, 190) Source(159, 28) + SourceIndex(0) -16>Emitted(80, 192) Source(159, 9) + SourceIndex(0) -17>Emitted(80, 234) Source(159, 28) + SourceIndex(0) -18>Emitted(80, 236) Source(160, 9) + SourceIndex(0) -19>Emitted(80, 255) Source(160, 32) + SourceIndex(0) -20>Emitted(80, 257) Source(160, 9) + SourceIndex(0) -21>Emitted(80, 303) Source(160, 32) + SourceIndex(0) -22>Emitted(80, 316) Source(162, 22) + SourceIndex(0) -23>Emitted(80, 317) Source(162, 23) + SourceIndex(0) -24>Emitted(80, 320) Source(162, 26) + SourceIndex(0) -25>Emitted(80, 321) Source(162, 27) + SourceIndex(0) -26>Emitted(80, 323) Source(162, 29) + SourceIndex(0) -27>Emitted(80, 324) Source(162, 30) + SourceIndex(0) -28>Emitted(80, 327) Source(162, 33) + SourceIndex(0) -29>Emitted(80, 328) Source(162, 34) + SourceIndex(0) -30>Emitted(80, 330) Source(162, 36) + SourceIndex(0) -31>Emitted(80, 331) Source(162, 37) + SourceIndex(0) -32>Emitted(80, 333) Source(162, 39) + SourceIndex(0) -33>Emitted(80, 335) Source(162, 41) + SourceIndex(0) -34>Emitted(80, 336) Source(162, 42) + SourceIndex(0) +6 >Emitted(80, 29) Source(157, 5) + SourceIndex(0) +7 >Emitted(80, 43) Source(157, 20) + SourceIndex(0) +8 >Emitted(80, 45) Source(157, 5) + SourceIndex(0) +9 >Emitted(80, 83) Source(157, 20) + SourceIndex(0) +10>Emitted(80, 85) Source(158, 5) + SourceIndex(0) +11>Emitted(80, 101) Source(161, 47) + SourceIndex(0) +12>Emitted(80, 103) Source(158, 5) + SourceIndex(0) +13>Emitted(80, 170) Source(161, 47) + SourceIndex(0) +14>Emitted(80, 172) Source(159, 9) + SourceIndex(0) +15>Emitted(80, 189) Source(159, 28) + SourceIndex(0) +16>Emitted(80, 191) Source(159, 9) + SourceIndex(0) +17>Emitted(80, 233) Source(159, 28) + SourceIndex(0) +18>Emitted(80, 235) Source(160, 9) + SourceIndex(0) +19>Emitted(80, 254) Source(160, 32) + SourceIndex(0) +20>Emitted(80, 256) Source(160, 9) + SourceIndex(0) +21>Emitted(80, 302) Source(160, 32) + SourceIndex(0) +22>Emitted(80, 309) Source(162, 22) + SourceIndex(0) +23>Emitted(80, 310) Source(162, 23) + SourceIndex(0) +24>Emitted(80, 313) Source(162, 26) + SourceIndex(0) +25>Emitted(80, 314) Source(162, 27) + SourceIndex(0) +26>Emitted(80, 316) Source(162, 29) + SourceIndex(0) +27>Emitted(80, 317) Source(162, 30) + SourceIndex(0) +28>Emitted(80, 320) Source(162, 33) + SourceIndex(0) +29>Emitted(80, 321) Source(162, 34) + SourceIndex(0) +30>Emitted(80, 323) Source(162, 36) + SourceIndex(0) +31>Emitted(80, 324) Source(162, 37) + SourceIndex(0) +32>Emitted(80, 326) Source(162, 39) + SourceIndex(0) +33>Emitted(80, 328) Source(162, 41) + SourceIndex(0) +34>Emitted(80, 329) Source(162, 42) + SourceIndex(0) --- >>> console.log(primaryA); 1 >^^^^ @@ -3296,35 +3272,35 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(82, 1) Source(164, 1) + SourceIndex(0) 2 >Emitted(82, 2) Source(164, 2) + SourceIndex(0) --- ->>>for (_58 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_59 = _58.name, name = _59 === void 0 ? "noName" : _59, _60 = _58.skills, _61 = _60 === void 0 ? { primary: "none", secondary: "none" } : _60, _62 = _61.primary, primary = _62 === void 0 ? "primary" : _62, _63 = _61.secondary, secondary = _63 === void 0 ? "secondary" : _63, _58), _58, +>>>for (_58 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _59 = _58.name, name = _59 === void 0 ? "noName" : _59, _60 = _58.skills, _61 = _60 === void 0 ? { primary: "none", secondary: "none" } : _60, _62 = _61.primary, primary = _62 === void 0 ? "primary" : _62, _63 = _61.secondary, secondary = _63 === void 0 ? "secondary" : _63, _58, 1-> 2 >^^^ 3 > ^ 4 > ^ 5 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -6 > ^^^ -7 > ^^^^^^^^^^^^^^ -8 > ^^ -9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -10> ^^ -11> ^^^^^^^^^^^^^^^^ -12> ^^ -13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -14> ^^ -15> ^^^^^^^^^^^^^^^^^ -16> ^^ -17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -18> ^^ -19> ^^^^^^^^^^^^^^^^^^^ -20> ^^ -21> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +6 > ^^ +7 > ^^^^^^^^^^^^^^ +8 > ^^ +9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +10> ^^ +11> ^^^^^^^^^^^^^^^^ +12> ^^ +13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +14> ^^ +15> ^^^^^^^^^^^^^^^^^ +16> ^^ +17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +18> ^^ +19> ^^^^^^^^^^^^^^^^^^^ +20> ^^ +21> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1-> > 2 >for @@ -3338,50 +3314,50 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } } 6 > -7 > name = "noName" -8 > -9 > name = "noName" -10> , - > -11> skills: { - > primary = "primary", - > secondary = "secondary" - > } = { primary: "none", secondary: "none" } -12> -13> skills: { - > primary = "primary", - > secondary = "secondary" - > } = { primary: "none", secondary: "none" } -14> -15> primary = "primary" -16> -17> primary = "primary" -18> , - > -19> secondary = "secondary" -20> -21> secondary = "secondary" +7 > name = "noName" +8 > +9 > name = "noName" +10> , + > +11> skills: { + > primary = "primary", + > secondary = "secondary" + > } = { primary: "none", secondary: "none" } +12> +13> skills: { + > primary = "primary", + > secondary = "secondary" + > } = { primary: "none", secondary: "none" } +14> +15> primary = "primary" +16> +17> primary = "primary" +18> , + > +19> secondary = "secondary" +20> +21> secondary = "secondary" 1->Emitted(83, 1) Source(165, 1) + SourceIndex(0) 2 >Emitted(83, 4) Source(165, 4) + SourceIndex(0) 3 >Emitted(83, 5) Source(165, 5) + SourceIndex(0) 4 >Emitted(83, 6) Source(165, 6) + SourceIndex(0) 5 >Emitted(83, 85) Source(171, 90) + SourceIndex(0) -6 >Emitted(83, 88) Source(166, 5) + SourceIndex(0) -7 >Emitted(83, 102) Source(166, 20) + SourceIndex(0) -8 >Emitted(83, 104) Source(166, 5) + SourceIndex(0) -9 >Emitted(83, 142) Source(166, 20) + SourceIndex(0) -10>Emitted(83, 144) Source(167, 5) + SourceIndex(0) -11>Emitted(83, 160) Source(170, 47) + SourceIndex(0) -12>Emitted(83, 162) Source(167, 5) + SourceIndex(0) -13>Emitted(83, 229) Source(170, 47) + SourceIndex(0) -14>Emitted(83, 231) Source(168, 9) + SourceIndex(0) -15>Emitted(83, 248) Source(168, 28) + SourceIndex(0) -16>Emitted(83, 250) Source(168, 9) + SourceIndex(0) -17>Emitted(83, 292) Source(168, 28) + SourceIndex(0) -18>Emitted(83, 294) Source(169, 9) + SourceIndex(0) -19>Emitted(83, 313) Source(169, 32) + SourceIndex(0) -20>Emitted(83, 315) Source(169, 9) + SourceIndex(0) -21>Emitted(83, 361) Source(169, 32) + SourceIndex(0) +6 >Emitted(83, 87) Source(166, 5) + SourceIndex(0) +7 >Emitted(83, 101) Source(166, 20) + SourceIndex(0) +8 >Emitted(83, 103) Source(166, 5) + SourceIndex(0) +9 >Emitted(83, 141) Source(166, 20) + SourceIndex(0) +10>Emitted(83, 143) Source(167, 5) + SourceIndex(0) +11>Emitted(83, 159) Source(170, 47) + SourceIndex(0) +12>Emitted(83, 161) Source(167, 5) + SourceIndex(0) +13>Emitted(83, 228) Source(170, 47) + SourceIndex(0) +14>Emitted(83, 230) Source(168, 9) + SourceIndex(0) +15>Emitted(83, 247) Source(168, 28) + SourceIndex(0) +16>Emitted(83, 249) Source(168, 9) + SourceIndex(0) +17>Emitted(83, 291) Source(168, 28) + SourceIndex(0) +18>Emitted(83, 293) Source(169, 9) + SourceIndex(0) +19>Emitted(83, 312) Source(169, 32) + SourceIndex(0) +20>Emitted(83, 314) Source(169, 9) + SourceIndex(0) +21>Emitted(83, 360) Source(169, 32) + SourceIndex(0) --- >>> i = 0; i < 1; i++) { 1 >^^^^ @@ -3458,13 +3434,12 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(86, 1) Source(174, 1) + SourceIndex(0) 2 >Emitted(86, 2) Source(174, 2) + SourceIndex(0) --- ->>>var _k, _q, _4, _9, _27, _33, _52, _58; ->>>var _a, _b, _c, _d, _e, _f, _g, _h, _j, _l, _m, _o, _p, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _5, _6, _7, _8, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _28, _29, _30, _31, _32, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _53, _54, _55, _56, _57, _59, _60, _61, _62, _63; +>>>var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63; >>>//# sourceMappingURL=sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js.map \ No newline at end of file