Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 6f274ea

Browse filesBrowse files
committed
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.
1 parent f437c8f commit 6f274ea
Copy full SHA for 6f274ea

4 files changed

+53-22Lines changed: 53 additions & 22 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/compiler/checker.ts‎

Copy file name to clipboardExpand all lines: src/compiler/checker.ts
+9-5Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11164,10 +11164,10 @@ namespace ts {
1116411164
return links.resolvedType;
1116511165
}
1116611166

11167-
function getObjectLiteralIndexInfo(node: ObjectLiteralExpression, properties: Symbol[], kind: IndexKind): IndexInfo {
11167+
function getObjectLiteralIndexInfo(propertyNodes: NodeArray<ObjectLiteralElementLike>, offset: number, properties: Symbol[], kind: IndexKind): IndexInfo {
1116811168
const propTypes: Type[] = [];
1116911169
for (let i = 0; i < properties.length; i++) {
11170-
if (kind === IndexKind.String || isNumericName(node.properties[i].name)) {
11170+
if (kind === IndexKind.String || isNumericName(propertyNodes[i + offset].name)) {
1117111171
propTypes.push(getTypeOfSymbol(properties[i]));
1117211172
}
1117311173
}
@@ -11193,7 +11193,10 @@ namespace ts {
1119311193
let hasComputedStringProperty = false;
1119411194
let hasComputedNumberProperty = false;
1119511195

11196-
for (const memberDecl of node.properties) {
11196+
let i = 0;
11197+
let offset = 0;
11198+
for (i = 0; i < node.properties.length; i++) {
11199+
const memberDecl = node.properties[i];
1119711200
let member = memberDecl.symbol;
1119811201
if (memberDecl.kind === SyntaxKind.PropertyAssignment ||
1119911202
memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ||
@@ -11262,6 +11265,7 @@ namespace ts {
1126211265
return unknownType;
1126311266
}
1126411267
spread = getSpreadType(spread, type, /*isFromObjectLiteral*/ false);
11268+
offset = i + 1;
1126511269
continue;
1126611270
}
1126711271
else {
@@ -11315,8 +11319,8 @@ namespace ts {
1131511319
return createObjectLiteralType();
1131611320

1131711321
function createObjectLiteralType() {
11318-
const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.String) : undefined;
11319-
const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.Number) : undefined;
11322+
const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.String) : undefined;
11323+
const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.Number) : undefined;
1132011324
const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
1132111325
const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
1132211326
result.flags |= TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags);
Collapse file

‎src/compiler/emitter.ts‎

Copy file name to clipboardExpand all lines: src/compiler/emitter.ts
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ var __assign = (this && this.__assign) || Object.assign || function(t) {
4545
const restHelper = `
4646
var __rest = (this && this.__rest) || function (s, e) {
4747
var t = {};
48-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && !e.indexOf(p))
48+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) === -1)
4949
t[p] = s[p];
5050
return t;
5151
};`;
Collapse file

‎src/compiler/transformers/destructuring.ts‎

Copy file name to clipboardExpand all lines: src/compiler/transformers/destructuring.ts
+42-16Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -304,25 +304,31 @@ namespace ts {
304304
if (properties.length !== 1) {
305305
// For anything but a single element destructuring we need to generate a temporary
306306
// to ensure value is evaluated exactly once.
307-
// When doing so we want to hightlight the passed in source map node since thats the one needing this temp assignment
307+
// When doing so we want to highlight the passed in source map node since that's the one needing this temp assignment
308308
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
309309
}
310310

311311
let bindingElements: ObjectLiteralElementLike[] = [];
312+
let computedTempVariables: Expression[];
312313
for (let i = 0; i < properties.length; i++) {
313314
const p = properties[i];
314315
if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) {
315316
if (!transformRest ||
316317
p.transformFlags & TransformFlags.ContainsSpreadExpression ||
317-
(p.kind === SyntaxKind.PropertyAssignment && p.initializer.transformFlags & TransformFlags.ContainsSpreadExpression)) {
318+
(p.kind === SyntaxKind.PropertyAssignment && p.initializer.transformFlags & TransformFlags.ContainsSpreadExpression) ||
319+
isComputedPropertyName(p.name)) {
318320
if (bindingElements.length) {
319321
emitRestAssignment(bindingElements, value, location, target);
320322
bindingElements = [];
321323
}
322324
const propName = <Identifier | LiteralExpression>(<PropertyAssignment>p).name;
323325
const bindingTarget = p.kind === SyntaxKind.ShorthandPropertyAssignment ? <ShorthandPropertyAssignment>p : (<PropertyAssignment>p).initializer || propName;
324326
// Assignment for bindingTarget = value.propName should highlight whole property, hence use p as source map node
325-
emitDestructuringAssignment(bindingTarget, createDestructuringPropertyAccess(value, propName), p);
327+
const propAccess = createDestructuringPropertyAccess(value, propName);
328+
if (isComputedPropertyName(propName)) {
329+
(computedTempVariables = computedTempVariables || []).push((propAccess as ElementAccessExpression).argumentExpression);
330+
}
331+
emitDestructuringAssignment(bindingTarget, propAccess, p);
326332
}
327333
else {
328334
bindingElements.push(p);
@@ -336,7 +342,7 @@ namespace ts {
336342
bindingElements = [];
337343
}
338344
const propName = (p as SpreadAssignment).expression as Identifier;
339-
const restCall = createRestCall(value, target.properties, p => p.name, target);
345+
const restCall = createRestCall(value, target.properties, p => p.name, target, computedTempVariables);
340346
emitDestructuringAssignment(propName, restCall, p);
341347
}
342348
}
@@ -413,17 +419,28 @@ namespace ts {
413419

414420
/** Given value: o, propName: p, pattern: { a, b, ...p } from the original statement
415421
* `{ a, b, ...p } = o`, create `p = __rest(o, ["a", "b"]);`*/
416-
function createRestCall<T extends Node>(value: Expression, elements: T[], getPropertyName: (element: T) => PropertyName, location: TextRange): Expression {
417-
const propertyNames: LiteralExpression[] = [];
422+
function createRestCall<T extends Node>(value: Expression, elements: T[], getPropertyName: (element: T) => PropertyName, location: TextRange, computedTempVariables: Expression[]): Expression {
423+
const propertyNames: Expression[] = [];
418424
for (let i = 0; i < elements.length - 1; i++) {
419-
if (isOmittedExpression(elements[i])) {
425+
const element = elements[i];
426+
if (isOmittedExpression(element)) {
420427
continue;
421428
}
422-
const str = <StringLiteral>createSynthesizedNode(SyntaxKind.StringLiteral);
423-
str.pos = location.pos;
424-
str.end = location.end;
425-
str.text = getTextOfPropertyName(getPropertyName(elements[i]));
426-
propertyNames.push(str);
429+
if (isComputedPropertyName(getPropertyName(element))) {
430+
// get the temp name and put that in there instead, like `_tmp + ""`
431+
const stringifiedTemp = <StringLiteral>createSynthesizedNode(SyntaxKind.StringLiteral);
432+
stringifiedTemp.pos = location.pos;
433+
stringifiedTemp.end = location.end;
434+
stringifiedTemp.text = "";
435+
propertyNames.push(createBinary(computedTempVariables.shift(), SyntaxKind.PlusToken, stringifiedTemp));
436+
}
437+
else {
438+
const str = <StringLiteral>createSynthesizedNode(SyntaxKind.StringLiteral);
439+
str.pos = location.pos;
440+
str.end = location.end;
441+
str.text = getTextOfPropertyName(getPropertyName(element));
442+
propertyNames.push(str);
443+
}
427444
}
428445
const args = createSynthesizedNodeArray([value, createArrayLiteral(propertyNames, location)]);
429446
return createCall(createIdentifier("__rest"), undefined, args);
@@ -522,6 +539,7 @@ namespace ts {
522539
const elements = name.elements;
523540
const numElements = elements.length;
524541
let bindingElements: BindingElement[] = [];
542+
let computedTempVariables: Expression[];
525543
for (let i = 0; i < numElements; i++) {
526544
const element = elements[i];
527545
if (isOmittedExpression(element)) {
@@ -533,12 +551,15 @@ namespace ts {
533551
bindingElements = [];
534552
}
535553
const restCall = createRestCall(value,
536-
name.elements,
554+
elements, // name.elements,
537555
element => (element as BindingElement).propertyName || <Identifier>(element as BindingElement).name,
538-
name);
556+
name,
557+
computedTempVariables);
539558
emitBindingElement(element, restCall);
540559
}
541-
else if (transformRest && !(element.transformFlags & TransformFlags.ContainsSpreadExpression)) {
560+
else if (transformRest &&
561+
!(element.transformFlags & TransformFlags.ContainsSpreadExpression) &&
562+
!isComputedPropertyName(element.propertyName || element.name)) {
542563
// do not emit until we have a complete bundle of ES2015 syntax
543564
bindingElements.push(element);
544565
}
@@ -548,8 +569,13 @@ namespace ts {
548569
bindingElements = [];
549570
}
550571
// Rewrite element to a declaration with an initializer that fetches property
572+
// TODO: Probably save the result of createDestructuringPropertyAccess if propName is a computed property
551573
const propName = element.propertyName || <Identifier>element.name;
552-
emitBindingElement(element, createDestructuringPropertyAccess(value, propName));
574+
const propAccess = createDestructuringPropertyAccess(value, propName);
575+
if (isComputedPropertyName(propName)) {
576+
(computedTempVariables = computedTempVariables || []).push((propAccess as ElementAccessExpression).argumentExpression);
577+
}
578+
emitBindingElement(element, propAccess);
553579
}
554580
}
555581
if (bindingElements.length) {
Collapse file

‎src/compiler/utilities.ts‎

Copy file name to clipboardExpand all lines: src/compiler/utilities.ts
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,7 @@ namespace ts {
12621262
case SyntaxKind.Decorator:
12631263
case SyntaxKind.JsxExpression:
12641264
case SyntaxKind.JsxSpreadAttribute:
1265+
case SyntaxKind.SpreadAssignment:
12651266
return true;
12661267
case SyntaxKind.ExpressionWithTypeArguments:
12671268
return (<ExpressionWithTypeArguments>parent).expression === node && isExpressionWithTypeArgumentsInClassExtendsClause(parent);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.