Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Object spread rest fixes #12248

Merged
merged 10 commits into from
Nov 15, 2016
Merged

Object spread rest fixes #12248

merged 10 commits into from
Nov 15, 2016

Conversation

sandersn
Copy link
Member

@sandersn sandersn commented Nov 15, 2016

Fixes #12211
Fixes #12200
Fixes #12227
Fixes #12228

New:
Fixes #12252

  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. 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.
Copy link
Member

@rbuckton rbuckton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few minor comments, but generally this looks fine.

@@ -11193,7 +11193,10 @@ namespace ts {
let hasComputedStringProperty = false;
let hasComputedNumberProperty = false;

for (const memberDecl of node.properties) {
let i = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it can probably be part of the following for declaration rather than on its own.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, left over from an earlier single-variable attempt.

@@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't >= 0 be a few less chars?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even less chars would be !~e.indexOf(p)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test is for not found. But I guess i could use < 0.

@timsuchanek Typescript's emit tries to balance readability, speed and brevity. Brevity is the least important of the three, though, and I think !~e.indexOf(p) is less readable than e.indexOf(p) < 0.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched to < 0.

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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the location for the literal? Also, why not just use createLiteral("", location)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird, last time I looked I thought createLiteral said that it returns NumericLiteral. You're right, that's much better.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what location is used for -- source maps, right? I'll leave it out of the createLiteral("") call for now and leave it in elsewhere.

propertyNames.push(createBinary(computedTempVariables.shift(), SyntaxKind.PlusToken, stringifiedTemp));
}
else {
const str = <StringLiteral>createSynthesizedNode(SyntaxKind.StringLiteral);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For StringLiteral and Identifier you can just call createLiteral(element), which creates a StringLiteral that reads its literal text from the original identifier. That way you can preserve unicode escape sequences. We could probably add support for NumericLiteral to createLiteral as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that's how I got confused. Tide for emacs doesn't display overloads and I got shown the number overload of createLiteral with no indication that there are others.

@@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this TODO something you still have yet to do for this PR or is it for future work?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's already done. I delete the TODO.

emitBindingElement(element, createDestructuringPropertyAccess(value, propName));
const propAccess = createDestructuringPropertyAccess(value, propName);
if (isComputedPropertyName(propName)) {
(computedTempVariables = computedTempVariables || []).push((propAccess as ElementAccessExpression).argumentExpression);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See append in core.ts:

computedTempVariables = append(computedTempVariables, (propAccess as ElementAccessExpression).argumentExpression);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the reminder. I keep forgetting about append.

@@ -1,42 +1,42 @@
=== tests/cases/conformance/types/rest/objectRest.ts ===
let o = { a: 1, b: 'no' }
>o : Symbol(o, Decl(objectRest.ts, 0, 3))
var o = { a: 1, b: 'no' }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these suddenly var and not let?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the source declaration (line 2) so I could reuse o in a destructuring assignment below.

stringifiedTemp.pos = location.pos;
stringifiedTemp.end = location.end;
stringifiedTemp.text = "";
propertyNames.push(createBinary(computedTempVariables.shift(), SyntaxKind.PlusToken, stringifiedTemp));
Copy link

@Jessidhia Jessidhia Nov 15, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will crash at runtime if the typeof of the key is "symbol".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you suggest toString instead?

Copy link

@Jessidhia Jessidhia Nov 15, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would crash with "number" / "undefined" / null instead :(

A workaround could be to use String() instead, as that will work with anything (and hopefully nobody actually has a string key that looks like "Symbol()"), but it would prevent easily improving __rest into being able to preserve (and filter) Symbol...

The most correct option would be typeof x == "symbol" ? x : String(x).

@sandersn sandersn merged commit d96a0ad into master Nov 15, 2016
@sandersn sandersn deleted the object-spread-rest-fixes branch November 15, 2016 20:32
@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants