mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 21:36:50 -05:00
Spread+rest fixes
1. Rename finds identifiers in spread assignment expressions. 2. Spreads with computed properties of type number or any no longer crash the compiler. 3. Rest emit uses indexOf === -1 instead of !indexOf to filter properties. 4. Rest emit correctly refers to computed properties' generated temps.
This commit is contained in:
@@ -11164,10 +11164,10 @@ namespace ts {
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function getObjectLiteralIndexInfo(node: ObjectLiteralExpression, properties: Symbol[], kind: IndexKind): IndexInfo {
|
||||
function getObjectLiteralIndexInfo(propertyNodes: NodeArray<ObjectLiteralElementLike>, offset: number, properties: Symbol[], kind: IndexKind): IndexInfo {
|
||||
const propTypes: Type[] = [];
|
||||
for (let i = 0; i < properties.length; i++) {
|
||||
if (kind === IndexKind.String || isNumericName(node.properties[i].name)) {
|
||||
if (kind === IndexKind.String || isNumericName(propertyNodes[i + offset].name)) {
|
||||
propTypes.push(getTypeOfSymbol(properties[i]));
|
||||
}
|
||||
}
|
||||
@@ -11193,7 +11193,10 @@ namespace ts {
|
||||
let hasComputedStringProperty = false;
|
||||
let hasComputedNumberProperty = false;
|
||||
|
||||
for (const memberDecl of node.properties) {
|
||||
let i = 0;
|
||||
let offset = 0;
|
||||
for (i = 0; i < node.properties.length; i++) {
|
||||
const memberDecl = node.properties[i];
|
||||
let member = memberDecl.symbol;
|
||||
if (memberDecl.kind === SyntaxKind.PropertyAssignment ||
|
||||
memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ||
|
||||
@@ -11262,6 +11265,7 @@ namespace ts {
|
||||
return unknownType;
|
||||
}
|
||||
spread = getSpreadType(spread, type, /*isFromObjectLiteral*/ false);
|
||||
offset = i + 1;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
@@ -11315,8 +11319,8 @@ namespace ts {
|
||||
return createObjectLiteralType();
|
||||
|
||||
function createObjectLiteralType() {
|
||||
const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.String) : undefined;
|
||||
const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.Number) : undefined;
|
||||
const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.String) : undefined;
|
||||
const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.Number) : undefined;
|
||||
const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
|
||||
const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
|
||||
result.flags |= TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags);
|
||||
|
||||
@@ -45,7 +45,7 @@ var __assign = (this && this.__assign) || Object.assign || function(t) {
|
||||
const restHelper = `
|
||||
var __rest = (this && this.__rest) || function (s, e) {
|
||||
var t = {};
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && !e.indexOf(p))
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) === -1)
|
||||
t[p] = s[p];
|
||||
return t;
|
||||
};`;
|
||||
|
||||
@@ -304,17 +304,19 @@ namespace ts {
|
||||
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
|
||||
// When doing so we want to highlight the passed in source map node since that's the one needing this temp assignment
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
|
||||
}
|
||||
|
||||
let bindingElements: ObjectLiteralElementLike[] = [];
|
||||
let computedTempVariables: Expression[];
|
||||
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)) {
|
||||
(p.kind === SyntaxKind.PropertyAssignment && p.initializer.transformFlags & TransformFlags.ContainsSpreadExpression) ||
|
||||
isComputedPropertyName(p.name)) {
|
||||
if (bindingElements.length) {
|
||||
emitRestAssignment(bindingElements, value, location, target);
|
||||
bindingElements = [];
|
||||
@@ -322,7 +324,11 @@ namespace ts {
|
||||
const propName = <Identifier | LiteralExpression>(<PropertyAssignment>p).name;
|
||||
const bindingTarget = p.kind === SyntaxKind.ShorthandPropertyAssignment ? <ShorthandPropertyAssignment>p : (<PropertyAssignment>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);
|
||||
const propAccess = createDestructuringPropertyAccess(value, propName);
|
||||
if (isComputedPropertyName(propName)) {
|
||||
(computedTempVariables = computedTempVariables || []).push((propAccess as ElementAccessExpression).argumentExpression);
|
||||
}
|
||||
emitDestructuringAssignment(bindingTarget, propAccess, p);
|
||||
}
|
||||
else {
|
||||
bindingElements.push(p);
|
||||
@@ -336,7 +342,7 @@ namespace ts {
|
||||
bindingElements = [];
|
||||
}
|
||||
const propName = (p as SpreadAssignment).expression as Identifier;
|
||||
const restCall = createRestCall(value, target.properties, p => p.name, target);
|
||||
const restCall = createRestCall(value, target.properties, p => p.name, target, computedTempVariables);
|
||||
emitDestructuringAssignment(propName, restCall, p);
|
||||
}
|
||||
}
|
||||
@@ -413,17 +419,28 @@ namespace ts {
|
||||
|
||||
/** 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<T extends Node>(value: Expression, elements: T[], getPropertyName: (element: T) => PropertyName, location: TextRange): Expression {
|
||||
const propertyNames: LiteralExpression[] = [];
|
||||
function createRestCall<T extends Node>(value: Expression, elements: T[], getPropertyName: (element: T) => PropertyName, location: TextRange, computedTempVariables: Expression[]): Expression {
|
||||
const propertyNames: Expression[] = [];
|
||||
for (let i = 0; i < elements.length - 1; i++) {
|
||||
if (isOmittedExpression(elements[i])) {
|
||||
const element = elements[i];
|
||||
if (isOmittedExpression(element)) {
|
||||
continue;
|
||||
}
|
||||
const str = <StringLiteral>createSynthesizedNode(SyntaxKind.StringLiteral);
|
||||
str.pos = location.pos;
|
||||
str.end = location.end;
|
||||
str.text = getTextOfPropertyName(getPropertyName(elements[i]));
|
||||
propertyNames.push(str);
|
||||
if (isComputedPropertyName(getPropertyName(element))) {
|
||||
// get the temp name and put that in there instead, like `_tmp + ""`
|
||||
const stringifiedTemp = <StringLiteral>createSynthesizedNode(SyntaxKind.StringLiteral);
|
||||
stringifiedTemp.pos = location.pos;
|
||||
stringifiedTemp.end = location.end;
|
||||
stringifiedTemp.text = "";
|
||||
propertyNames.push(createBinary(computedTempVariables.shift(), SyntaxKind.PlusToken, stringifiedTemp));
|
||||
}
|
||||
else {
|
||||
const str = <StringLiteral>createSynthesizedNode(SyntaxKind.StringLiteral);
|
||||
str.pos = location.pos;
|
||||
str.end = location.end;
|
||||
str.text = getTextOfPropertyName(getPropertyName(element));
|
||||
propertyNames.push(str);
|
||||
}
|
||||
}
|
||||
const args = createSynthesizedNodeArray([value, createArrayLiteral(propertyNames, location)]);
|
||||
return createCall(createIdentifier("__rest"), undefined, args);
|
||||
@@ -522,6 +539,7 @@ namespace ts {
|
||||
const elements = name.elements;
|
||||
const numElements = elements.length;
|
||||
let bindingElements: BindingElement[] = [];
|
||||
let computedTempVariables: Expression[];
|
||||
for (let i = 0; i < numElements; i++) {
|
||||
const element = elements[i];
|
||||
if (isOmittedExpression(element)) {
|
||||
@@ -533,12 +551,15 @@ namespace ts {
|
||||
bindingElements = [];
|
||||
}
|
||||
const restCall = createRestCall(value,
|
||||
name.elements,
|
||||
elements, // name.elements,
|
||||
element => (element as BindingElement).propertyName || <Identifier>(element as BindingElement).name,
|
||||
name);
|
||||
name,
|
||||
computedTempVariables);
|
||||
emitBindingElement(element, restCall);
|
||||
}
|
||||
else if (transformRest && !(element.transformFlags & TransformFlags.ContainsSpreadExpression)) {
|
||||
else if (transformRest &&
|
||||
!(element.transformFlags & TransformFlags.ContainsSpreadExpression) &&
|
||||
!isComputedPropertyName(element.propertyName || element.name)) {
|
||||
// do not emit until we have a complete bundle of ES2015 syntax
|
||||
bindingElements.push(element);
|
||||
}
|
||||
@@ -548,8 +569,13 @@ namespace ts {
|
||||
bindingElements = [];
|
||||
}
|
||||
// Rewrite element to a declaration with an initializer that fetches property
|
||||
// TODO: Probably save the result of createDestructuringPropertyAccess if propName is a computed property
|
||||
const propName = element.propertyName || <Identifier>element.name;
|
||||
emitBindingElement(element, createDestructuringPropertyAccess(value, propName));
|
||||
const propAccess = createDestructuringPropertyAccess(value, propName);
|
||||
if (isComputedPropertyName(propName)) {
|
||||
(computedTempVariables = computedTempVariables || []).push((propAccess as ElementAccessExpression).argumentExpression);
|
||||
}
|
||||
emitBindingElement(element, propAccess);
|
||||
}
|
||||
}
|
||||
if (bindingElements.length) {
|
||||
|
||||
@@ -1262,6 +1262,7 @@ namespace ts {
|
||||
case SyntaxKind.Decorator:
|
||||
case SyntaxKind.JsxExpression:
|
||||
case SyntaxKind.JsxSpreadAttribute:
|
||||
case SyntaxKind.SpreadAssignment:
|
||||
return true;
|
||||
case SyntaxKind.ExpressionWithTypeArguments:
|
||||
return (<ExpressionWithTypeArguments>parent).expression === node && isExpressionWithTypeArgumentsInClassExtendsClause(parent);
|
||||
|
||||
Reference in New Issue
Block a user