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 rest #12028

Merged
merged 16 commits into from
Nov 10, 2016
Merged

Object rest #12028

merged 16 commits into from
Nov 10, 2016

Conversation

sandersn
Copy link
Member

@sandersn sandersn commented Nov 3, 2016

Leaves #10727 still open
Fixes #2103

Add object rest syntax as specified in the stage 3 proposal.

Note:

  1. This does not include a rest type or a difference type. Rest syntax does not work if the rest target is not an object type. For example, type parameters do not work. We expect rest types or something similar in future versions of TypeScript.
  2. The PR is relative to object-spread, not master. Mostly this is so I don't have to duplicate transformers/esnext.ts and the build file updates. I expect object-spread to go in first so it shouldn't make a difference.

@sandersn
Copy link
Member Author

sandersn commented Nov 3, 2016

@ahejlsberg @mhegazy do you want to take a look at this after the object-spread PR?

}
for (const prop of getPropertiesOfType(source)) {
const inNamesToRemove = prop.name in names;
const isPrivate = getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected);
Copy link
Contributor

Choose a reason for hiding this comment

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

why are we removing private? it will exist at runtime, we do not create it as enumerable: false, and it not a parent property.

Copy link
Contributor

Choose a reason for hiding this comment

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

well.. this is actually different from what we do with keyof where we filter privates 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.

Spread also removes privates. It's the right thing to do there, and I think it is here too:

class P { private p: number }
let p: P;
var { ...exposed } = p;

I don't think exposed should be an easy way to get all of P's private members.

Copy link
Member

@ahejlsberg ahejlsberg left a comment

Choose a reason for hiding this comment

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

Make sure you have @rbuckton look at the emitter changes.

while (root && root.kind !== SyntaxKind.BinaryExpression) {
root = root.parent;
}
emitFlags |= root && isDestructuringAssignment(root) ? NodeFlags.HasRestAttribute : NodeFlags.HasSpreadAttribute;
Copy link
Member

Choose a reason for hiding this comment

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

I'm not 100% sure this is right. You might be walking up from the right side of a destructuring assignment, in which case the spread is actually a spread.

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 improved it to check that the relation between root and parent is that the object literal is the lefthand side.

const restHelper = `
var __rest = (this && this.__rest) || function (s, e) {
var t = {};

Copy link
Member

Choose a reason for hiding this comment

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

No blank lines in the helpers.

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

)
);
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Wow, that's an awful lot of code. I'm surprised it takes this much, but I'm not familiar enough with the new emitter to truly evaluate this. Make sure you have @rbuckton take a look.

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 copied from ES2015's function and for-of transforms, then simplified. I'll go back and see whether the two can share the code 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 moved a lot of shared code from ES2015 and ESNext to factory.ts. ESNext is a lot shorter now.

const restHelper = `
var __rest = (this && this.__rest) || function (s, e) {
var t = {};

Copy link
Contributor

Choose a reason for hiding this comment

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

nit. remove empty line

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

1. Remove extra line in __rest shim.
2. Improve __rest vs __assign check for destructuring assignment.
It is shared by es2015 and esNext transformers.

This commit just adds a convertObjectRest flag to be passed on to
flattenDestructuring functions, as well as adding necessary parameters
to use the code outside a transformer.
* Transforms the body of a function-like node.
*
* @param node A function-like node.
*/
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 only changes here are to add extra parameters needed to use transformFunctionBody and friends outside of a transformer, and to pass along convertObjectRest to flattenParameterDestructuring.

//
// for (let v of arr) { }
//
// we don't want to emit a temporary variable for the RHS, just use it directly.
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 only changes to convertForOf are

  1. in creating counter and elementAccess
  2. calling flattenParameterDestructuring with convertObjectRest
  3. calling createForOf vs createFor depending on whether convertObjectRest is true.

Otherwise it's just moved from es2015

@sandersn
Copy link
Member Author

sandersn commented Nov 4, 2016

@dotnet-bot test this please

Previously array destructuring inside an object destructuring with an
object rest would downlevel the array destructuring to ES5. This breaks
if the code that targets ES2015 is using iterators instead of arrays
since iterators don't support [0] or .slice that the ES5 emit uses.
Now with object destructuring inside array destructuring inside object
destructuring! Each with their own array/object rest!

Also updates baselines.
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.

The emit looks good, based on our offline discussion of the runtime semantics.

@@ -42,6 +42,14 @@ var __assign = (this && this.__assign) || Object.assign || function(t) {
return t;
};`;

const restHelper = `
var __rest = (this && this.__rest) || function (s, e) {
Copy link
Contributor

Choose a reason for hiding this comment

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

we will need to add this to https://github.com/Microsoft/tslib

Copy link
Contributor

Choose a reason for hiding this comment

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

also you will need a check in checker.ts for __rest and __assign, and add some tests for these.

@sandersn sandersn merged commit 25462c9 into object-spread Nov 10, 2016
@sandersn sandersn deleted the object-rest branch November 10, 2016 17:18
@sveisvei
Copy link

Great success!

@lgleim
Copy link

lgleim commented Nov 10, 2016

Wohoo! Awesome :)

@damianobarbati
Copy link

damianobarbati commented Nov 14, 2016

How is the object spread operator going to deal with nested objects?
Is it going to clone them or is it going to pass the reference?

Babel-kindaof-bugged example:

'use strict';

let a = { first: 1, next: { two: 2 } };
let b = { ...a };
b.first = 11;
b.next.two = 22;

//here we get a.next.two = 22 instead of 2!
console.log('a =', a);
console.log('b =', b);

@alitaheri
Copy link

@damianobarbati This is the correct behavior. That's how it works. { ...a } will create a shallow clone, not a deep clone. If you want a deep clone you can use lodash. { ...a } is equivalent to Object.assign({}, a) as per spec.

@damianobarbati
Copy link

Ok, just like current array spread operator then. Thanks @alitaheri

@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.

None yet

9 participants