-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Normative: Remove ToUint32 from array literal evaluation #1124
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, thanks!
If ToUint32 is simply removed, the problem (unspecified behaviour for too large values when ToString is called) noted in #1095 (comment) will arise:
|
@anba I see; I was imagining that these were Numbers, but of course they are mathematical values. I'd be fine waiting to land this patch until after the fix to tc39/proposal-bigint#10 lands, which will make them Numbers. |
@GeorgNeis and I discussed this change a bit further. Maybe the semantics here are a little off the mark--would it make more sense if we went with one version of @anba 's proposed semantics and used |
c584571
to
3bf3e39
Compare
This patch follows @GeorgNeis's suggestion from tc39#1124 (comment) In particular, the idea is that if you have an array literal which is longer than 2**32 elements, then the overflowing elements will just be ordinary properties, without throwing an exception. However, if the array has trailing holes, the semantics here correspond to an explicit set of the length, and an exception will be thrown
Uploaded a new version which attempts to specify the semantics from #1124 (comment) . @GeorgNeis What do you think? |
spec.html
Outdated
1. Perform Set(_array_, `"length"`, ToUint32(_pad_), *false*). | ||
1. NOTE: The above Set cannot fail because of the nature of the object returned by ArrayCreate. | ||
1. Perform ? Set(_array_, `"length"`, _pad_, *true*). | ||
1. NOTE: The above Set may throw in the case of an Array literal's padding exceeds 2<sup>32</sup>-1 elements. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/exceeds/exceeding/
or better s/may throw in the case of an Array literal's/throws if the/
OK, @GeorgNeis had some more suggestions, which seem really on point to me. The result is a simpler and more obviously correct version, which is sightly different in semantics in even more obscure edge cases, but which I prefer. I've uploaded a commit from him to this PR, and edited the PR description to match the current proposal. If/when this PR lands, please squash the commits and use the description above as the commit message (minus the Given resource limits on all JS implementations Georg and I tested, we could not find a way to differentiate the current semantics from the semantics proposed in this patch (or the alternatives previously considered). I'd say, unfortunately, test262 tests will not be useful for this PR, and we should consider landing it without tests or implementations. |
Any thoughts on this PR? What more is needed to decide whether it's ready to merge? |
Given that it's normative, it seems like it needs consensus (along with a rebase) |
@ljharb Feel free to land all of those suggestions. Somehow, the GitHub UI won't let me commit them. |
Previously, array literals (including spreads) had their indices and lengths calculated with a ToUint32 operation. As Georg Neis noted in tc39#1095, such a calculation isn't quite right, as 2**32-1 is not an array index. These semantics are unlikely to be observable in many current JavaScript implementations due to resource limitations, but the strange behavior may appear in future, resource-rich implementations. This patch takes Allen Wirfs-Brock's suggestion to simply remove the ToUint32 wraparounds and write to larger indices. When the length is written to, it will throw an exception, after having exhausted any iterators in the literal. Note that too-long Array literals throw only as a runtime exception, not as an early error. In the theoretical case of array indices which exceed the safe numerical integer range, the same semantics will apply--the iterator will be exhausted, and then the write to the length will throw. Internally, the same index will be written repeatedly. This patch includes appropriate use of ? and ! in modified operations.
This patch follows @GeorgNeis's suggestion from tc39#1124 (comment) In particular, the idea is that if you have an array literal which is longer than 2**32 elements, then the overflowing elements will just be ordinary properties, without throwing an exception. However, if the array has trailing holes, the semantics here correspond to an explicit set of the length, and an exception will be thrown
c3e1d47
to
bdcd531
Compare
Previously, array literals (including spreads) had their indices and lengths calculated with a ToUint32 operation. As Georg Neis noted in tc39#1095, such a calculation isn't quite right, as 2**32-1 is not an array index. These semantics are unlikely to be observable in many current JavaScript implementations due to resource limitations, but the strange behavior may appear in future, resource-rich implementations. This patch specifies Georg Neis's suggestion for semantics: to write to the length just in the case of elisions (regardless of where they are in the Array literal), and don't bother to write to the length for writes for ordinary elements (as Array indices will already lead to length updates). As a bonus, the semantics for Array literals are singificantly simplified, involving just one syntax-directed operation and pass rather than two. Note that, as before, too-long Array literals throw only as a runtime exception, not as an early error. This patch includes appropriate use of ? and ! in modified operations. Co-authored-by: Daniel Ehrenberg <littledan@chromium.org> Co-authored-by: Georg Neis <neis@chromium.org>
PR tc39#1124 removed the element-id 'sec-static-semantics-elisionwidth'. Reinstate it as an 'oldid'.
PR tc39#1124 removed the element-id 'sec-static-semantics-elisionwidth'. Reinstate it as an 'oldid'.
- Add a subscript R: Since _intValue_ is to be treated as a mathematical value, we should be comparing it to a mathematical zero. - Reinstate 'sec-static-semantics-elisionwidth' as an oldid; tc39#1124 removed the element-id 'sec-static-semantics-elisionwidth' - Reinstate 'sec-synchronizeeventset' as an oldid; tc39#1692 removed the element-id 'sec-synchronizeeventset'. - Reference 'ExportFromClause' from Annex A; tc39#1174 introduced the nonterminal 'ExportFromClause', but didn't reference it from Annex A. - Put asterisks around 'true' (from tc39#1716) - Fix typo "_eventRecords_" -> "_eventsRecord_" (from tc39#1692)
Previously, array literals (including spreads) had their indices and
lengths calculated with a ToUint32 operation. As Georg Neis noted
in #1095, such a calculation isn't quite right, as 2**32-1 is not
an array index. These semantics are unlikely to be observable in many
current JavaScript implementations due to resource limitations, but
the strange behavior may appear in future, resource-rich
implementations.
This patch specifies Georg Neis's suggestion for semantics: to write to
the length just in the case of elisions (regardless of where they are in
the Array literal), and don't bother to write to the length for writes for
ordinary elements (as Array indices will already lead to length updates).
As a bonus, the semantics for Array literals are singificantly simplified, involving
just one syntax-directed operation and pass rather than two. Note that, as before,
too-long Array literals throw only as a runtime exception, not as an early error.
This patch includes appropriate use of ? and ! in modified operations.
cc @allenwb @GeorgNeis @anba