RESOLVED FIXED Bug 147677
Ensure that Reflect.enumerate does not produce the deleted keys
https://bugs.webkit.org/show_bug.cgi?id=147677
Summary Ensure that Reflect.enumerate does not produce the deleted keys
Jordan Harband
Reported 2015-08-04 21:20:23 PDT
Given this code: ``` var obj = {a: 1, b: 2}; var iterator = Reflect.enumerate(obj); obj.c = 3; assert.deepEqual(Array.from(iterator), ['a', 'b', 'c']); ``` Webkit will fail (specifically, it won't yield the "c" key, because it was added after the iterator was created). According to the spec, keys should be determined at each `next` call - and any unvisited key, that's added before the first `next` call, must therefore be visitable (assuming I'm reading the spec right)
Attachments
Patch (2.12 KB, patch)
2015-08-10 21:55 PDT, Yusuke Suzuki
no flags
Yusuke Suzuki
Comment 1 2015-08-05 00:04:42 PDT
Hm, I'm not sure this is true in the spec. http://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-enumerate Which part is corresponding to this issue?
Jordan Harband
Comment 2 2015-08-05 00:15:39 PDT
I read "The iterator’s next method processes object properties to determine whether the property key should be returned as an iterator value" as, only "next" should look at properties. The generator function example in fact will not process the function body until the first `next` is called - which means, `Reflect.ownKeys` is not called until that first `next` - which means that prior to the first `next` call, any and all key changes should be reflected in the upcoming `ownKeys` call.
Darin Adler
Comment 3 2015-08-08 13:59:11 PDT
Is there a way to make changes to properties after the first time next is called but before the second time next is called? Do we handle that properly? Are there tests covering that?
Yusuke Suzuki
Comment 4 2015-08-08 22:31:20 PDT
(In reply to comment #3) > Is there a way to make changes to properties after the first time next is > called but before the second time next is called? Do we handle that > properly? Are there tests covering that? If you delete the property name from the object, the deleted name is not produced by the iterator. This behavior is specified in the spec. "A property that is deleted before it is processed by the iterator’s next method is ignored." And if you add the property name to the object after calling next(), this name may or may not be produced by the iterator. "If new properties are added to the target object during enumeration, the newly added properties are not guaranteed to be processed in the active enumeration." In WebKit's implementation, we don't produce it. And actually, our implementation works correctly on them. > Are there tests covering that? Oops, maybe, I didn't add the test for them. It's my fault. I need to add tests anyway.
Yusuke Suzuki
Comment 5 2015-08-08 22:50:21 PDT
(In reply to comment #2) > I read "The iterator’s next method processes object properties to determine > whether the property key should be returned as an iterator value" as, only > "next" should look at properties. > > The generator function example in fact will not process the function body > until the first `next` is called - which means, `Reflect.ownKeys` is not > called until that first `next` - which means that prior to the first `next` > call, any and all key changes should be reflected in the upcoming `ownKeys` > call. Still I'm not confident that which behavior is correct because I think the spec is slightly ambiguous on this. (Maybe, I've missed something. And Darin, what do you think of?) I'd like to ask about this to the es-discuss to ensure the correct behavior, OK? The spec says "If new properties are added to the target object during enumeration, the newly added properties are not guaranteed to be processed in the active enumeration.". In for-in, we first call [[Enumerate]] in http://www.ecma-international.org/ecma-262/6.0/#sec-runtime-semantics-forin-div-ofheadevaluation-tdznames-expr-iterationkind. So if [[Enumerate]] call is included in the "active enumeration" process, I think that we can say caching the all property names at first is the correct implementation. In the current implementation, I think we can say that "The iterator’s next method processes object properties to determine whether the property key should be returned as an iterator value" is correct if the initialization is included in the "active enumeration". And for the generator's implementation, we have notes. "NOTE The following is an informative definition of an ECMAScript generator function that conforms to these rules:" So I think this example implementation just follow the rules specified in the spec. But if the rule doesn't say anything about the iterator's initialization time, this generator's implementation is just the example. In that case, this is the implementation dependent, both (our implementation and generator example) are correct.
Jordan Harband
Comment 6 2015-08-09 10:10:56 PDT
(In reply to comment #5) Absolutely we should clarify with es-discuss. However, enumeration of a generator does not start until the first time "next" is called - since the canonical example in the spec is itself a generator (one of the rare times code is supplied in the spec), it's pretty clear to be that up until the first "next" call, no keys should be cached. You're absolutely right that after the first "next" is called, any keys deleted before being yielded, will not be yielded - and any keys added may or may not be yielded, up to the implementation.
Darin Adler
Comment 7 2015-08-09 17:56:08 PDT
We should definitely have this discussion with the others in es-discuss. It’s peculiar design to require behavior where added keys before the first call to "next" are guaranteed to be iterated, but where added keys before other calls to "next" might or might not be. Doesn’t seem obviously better to make the first call to "next" special and different from the others, as opposed to making the key moment the time when the object is created. Also strange that the model specifies exactly this degree of laziness but leave behavior for added keys between calls to "next" undefined; would be better to have it specified one way or another rather than left to each implementer to do differently, unless there is a substantial advantage to leaving this undefined. This kind of undefined behavior often leads to real world incompatibilities, so we should avoid it if we can. Any chance we could get this refined to be something more logical?
Yusuke Suzuki
Comment 8 2015-08-10 12:11:59 PDT
https://esdiscuss.org/topic/question-about-enumerate-and-property-decision-timing Now, let's just add the tests to ensure that deleted key before producing the key is not produced.
Jordan Harband
Comment 9 2015-08-10 12:31:22 PDT
Glad we clarified it :-) I'll update the es6-shim's tests and implementation.
Yusuke Suzuki
Comment 10 2015-08-10 21:54:40 PDT
(In reply to comment #9) > Glad we clarified it :-) I'll update the es6-shim's tests and implementation. Nice :D
Yusuke Suzuki
Comment 11 2015-08-10 21:55:26 PDT
Yusuke Suzuki
Comment 12 2015-08-10 23:46:07 PDT
Comment on attachment 258702 [details] Patch Thank you for your review!
WebKit Commit Bot
Comment 13 2015-08-11 00:36:37 PDT
Comment on attachment 258702 [details] Patch Clearing flags on attachment: 258702 Committed r188253: <http://trac.webkit.org/changeset/188253>
WebKit Commit Bot
Comment 14 2015-08-11 00:36:41 PDT
All reviewed patches have been landed. Closing bug.
Note You need to log in before you can comment on or make changes to this bug.