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

Preserve empty for...of loops #3132

Merged
merged 13 commits into from Sep 26, 2019
21 changes: 12 additions & 9 deletions src/ast/nodes/ForOfStatement.ts
@@ -1,6 +1,6 @@
import MagicString from 'magic-string';
import { NO_SEMICOLON, RenderOptions } from '../../utils/renderHelpers';
import { ExecutionPathOptions } from '../ExecutionPathOptions';
// import { ExecutionPathOptions } from '../ExecutionPathOptions';
import BlockScope from '../scopes/BlockScope';
import Scope from '../scopes/Scope';
import { EMPTY_PATH } from '../values';
Expand All @@ -27,14 +27,17 @@ export default class ForOfStatement extends StatementBase {
this.scope = new BlockScope(parentScope);
}

hasEffects(options: ExecutionPathOptions): boolean {
return (
(this.left &&
(this.left.hasEffects(options) ||
this.left.hasEffectsWhenAssignedAtPath(EMPTY_PATH, options))) ||
(this.right && this.right.hasEffects(options)) ||
this.body.hasEffects(options.setIgnoreBreakStatements())
);
hasEffects(/* options: ExecutionPathOptions */): boolean {
// Placeholder until proper Symbol.Iterator support
return true;

// return (
// (this.left &&
// (this.left.hasEffects(options) ||
// this.left.hasEffectsWhenAssignedAtPath(EMPTY_PATH, options))) ||
// (this.right && this.right.hasEffects(options)) ||
// this.body.hasEffects(options.setIgnoreBreakStatements())
// );
Copy link
Member

Choose a reason for hiding this comment

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

Could you get rid of the commented code and commented import?

}

include(includeChildrenRecursively: IncludeChildren) {
Expand Down
3 changes: 3 additions & 0 deletions test/function/samples/preserve-for-of-iterable/_config.js
@@ -0,0 +1,3 @@
module.exports = {
description: 'preserves for...of loops'
};
18 changes: 18 additions & 0 deletions test/function/samples/preserve-for-of-iterable/iterables.js
@@ -0,0 +1,18 @@
export const zeroToFive = {
[Symbol.iterator]() {
return {
current: 0,
last: 5,
next() {
const ret = this.current < this.last
? { done: false, value: this.current++ }
: { done: true };

// assert later
global.foo = this.current;
Copy link
Member

Choose a reason for hiding this comment

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

A cooler way than mutating a global and testing our test isolation would be to export a mutable export let ... binding and checking that.


return ret;
}
};
}
};
19 changes: 19 additions & 0 deletions test/function/samples/preserve-for-of-iterable/loops.js
@@ -0,0 +1,19 @@
export const awaitable = async (iterable) => {
for await (const value of iterable) {
}
}

// This is equivalent to the above 'awaitable' function.
export const equivalent = async (iterable) => {
const iterator = iterable[Symbol.asyncIterator]()
let { done } = await iterator.next()
while (!done) {
({ done } = await iterator.next())
}

}

export const iterate = iterable => {
for (const value of iterable) {
}
}
6 changes: 6 additions & 0 deletions test/function/samples/preserve-for-of-iterable/main.js
@@ -0,0 +1,6 @@
import { zeroToFive } from './iterables';
import { iterate } from './loops';

assert.equal(global.foo, undefined);
iterate(zeroToFive);
assert.equal(global.foo, 5);