-
Notifications
You must be signed in to change notification settings - Fork 154
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: Audit of user-visible operations in Temporal #2519
Conversation
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## main #2519 +/- ##
========================================
Coverage 96.35% 96.36%
========================================
Files 20 21 +1
Lines 12196 12535 +339
Branches 2274 2346 +72
========================================
+ Hits 11752 12079 +327
- Misses 389 401 +12
Partials 55 55
☔ View full report in Codecov by Sentry. |
63c4b04
to
a2f79ba
Compare
The Calendar Record commit landed on this PR a couple of hours after the official TC39 agenda deadline. If this interferes with your review of this PR, please let me know; I'm happy to go over it with you. |
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.
I'm amazed that any single human being made a PR of this scope. Very impressive work here. It's like running a nerdy ultra-marathon!
I focused my review of the logic on the polyfill code, and assumed that the spec matched the polyfill because I was exhausted by the time I got to the spec part. :-)
Only a few minor comments/nits.
When GetMethod is used to lookup the dateAdd or dateUntil method of a calendar, we need to account for the case where the calendar is a builtin calendar represented by a string. This was an oversight in #2482. In hindsight, the lookups of dateAdd and dateUntil in BalanceDurationRelative should have been grouped together as they were in UnbalanceDurationRelative. But since that will be addressed anyway by the Calendar Method Records in the yet-to-be-merged PR #2519, I'm not planning to change that here. Closes: #2547
When GetMethod is used to lookup the dateAdd or dateUntil method of a calendar, we need to account for the case where the calendar is a builtin calendar represented by a string. This was an oversight in #2482. In hindsight, the lookups of dateAdd and dateUntil in BalanceDurationRelative should have been grouped together as they were in UnbalanceDurationRelative. But since that will be addressed anyway by the Calendar Method Records in the yet-to-be-merged PR #2519, I'm not planning to change that here. Closes: #2547
When GetMethod is used to lookup the dateAdd or dateUntil method of a calendar, we need to account for the case where the calendar is a builtin calendar represented by a string. This was an oversight in #2482. In hindsight, the lookups of dateAdd and dateUntil in BalanceDurationRelative should have been grouped together as they were in UnbalanceDurationRelative. But since that will be addressed anyway by the Calendar Method Records in the yet-to-be-merged PR #2519, I'm not planning to change that here. Closes: #2547
Just as in CalendarDateAdd and CalendarDateUntil, add optional parameters to GetPossibleInstantsFor and GetOffsetNanosecondsFor which can supply the method to be called, in case the caller has already looked it up. This doesn't make any observable change, but it will be used for optimizations in #2519.
Do the same for CalendarDateFromFields as in CalendarDateAdd and CalendarDateUntil: add an optional parameter to CalendarFields which can supply the method to be called, in case the caller has already looked it up. This doesn't make any observable change, but it will be used for optimizations in #2519.
a2f79ba
to
717d602
Compare
I rebased this and it's now stacked on top of #2562. There are still some review comments left to address. |
Just as in CalendarDateAdd and CalendarDateUntil, add optional parameters to GetPossibleInstantsFor and GetOffsetNanosecondsFor which can supply the method to be called, in case the caller has already looked it up. This doesn't make any observable change, but it will be used for optimizations in #2519.
Do the same for CalendarDateFromFields as in CalendarDateAdd and CalendarDateUntil: add an optional parameter to CalendarFields which can supply the method to be called, in case the caller has already looked it up. This doesn't make any observable change, but it will be used for optimizations in #2519.
5e0c619
to
a656703
Compare
f5540ce
to
c68dccc
Compare
584fd67
to
ac190ac
Compare
d54febf
to
7ec6df3
Compare
7ec6df3
to
f77ca4e
Compare
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.
There are a couple of cases where assertions are backwards or prose in descriptions differs from assertions in the text; see comments. The rest of my comments are editorial questions/suggestions only. Beyond those couple of minor conditionals, this all looks great and correct to me, and makes the user code interactions a lot more predictable. I'd say, ship it!
</dd> | ||
</dl> | ||
<emu-alg> | ||
1. Assert: IsValidISODate(_year_, _month_, _day_) is *true*. | ||
1. Let _dateTime_ be ? CreateTemporalDateTime(_year_, _month_, _day_, _hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_, *"iso8601"*). | ||
1. If _offsetBehaviour_ is ~wall~ or _offsetOption_ is *"ignore"*, then | ||
1. Let _instant_ be ? GetInstantFor(_timeZone_, _dateTime_, _disambiguation_). | ||
1. Assert: TimeZoneMethodsRecordHasLookedUp(_timeZoneRec_, ~getPossibleInstantsFor~) is *true*. |
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.
This assertion conflicts with the paragraph added above to the operation's description.
This path can be taken if _offsetBehavior_
is ~exact~
and _offsetOption_
is *"ignore"*
, or if _offsetOption_
is *"use"*
and _offsetBehavior_
is ~wall~
.
In all uses of this abstract operation, the assertion won't be violated, but the paragraph above still editorially conflicts with the assertion step, since ~wall~
or *"ignore"*
are checked first.
I think a more accurate version would be:
Unless (_offsetBehavior_ is ~exact~ or _offsetOption_ is *"use"*) and (_offsetBehavior is not ~wall~ and _offsetOption~ is not *"ignore"*), ...
But that sounds unwieldy. I think there's a better way to place this assertion / order these tests, but maybe that'd move some observable effects around or affect the results?
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.
For now I'll remove the prose description. I'll submit a separate editorial change to clarify that offsetOption should be ignored unless offsetBehaviour is ~option~
.
Introduce a new spec type, Time Zone Methods Record, which stores a time zone object's getOffsetNanosecondsFor and getPossibleInstantsFor methods once they have been observably looked up. The record is passed around into abstract operations instead of the time zone object itself. Most API operations that do time zone calculations need to look up both getOffsetNanosecondsFor and getPossibleInstantsFor unconditionally. Only in the case where we convert a plain time to an exact time, it's possible we only need to look up getPossibleInstantsFor, or neither (if the offset is supplied.) This is a large commit but most of it is mechanical replacement of Temporal.TimeZone variables with Time Zone Record variables.
Introduce a new spec type, Calendar Methods Record, which stores a calendar object's methods once they have been observably looked up. The record is passed around into abstract operations instead of the calendar object itself. The mechanism doesn't currently allow for storing all Temporal.Calendar methods, only the ones that are explicitly called internally in other places than the Zoned and Plain types' methods of the same name, as part of a different API call. Some methods not included in the record are only called by the same-named methods on other Temporal types (example, Calendar.p.dayOfWeek is only called by ZonedDateTime.p.dayOfWeek, PlainDateTime.p.dayOfWeek, and PlainDate.p.dayOfWeek.) Other methods not included in the record are potentially called through lookups in PrepareTemporalFields, so it's not possible to pre-fetch them without making polyfilling difficult. (Example, Calendar.p.monthCode is called in `plainYearMonth.toPlainDate(...)` by looking up the `plainYearMonth.monthCode` property in PrepareTemporalFields. Shortcutting that lookup would mean that PlainDate.p.monthCode could never be polyfilled.) This is a large commit but most of it is mechanical replacement of Temporal.Calendar variables with Calendar Methods Record variables.
This is an addendum to part 3 (#2671) that removes a ZonedDateTime to PlainDateTime conversion in one place where a fast path doesn't need the PlainDateTime. This is observable in the case where you add or subtract two Temporal.Durations that don't have any units higher than hours. Credit to Anba for spotting this. Closes: #2696
f77ca4e
to
8234ec4
Compare
Thanks for the review! We did get some last-minute improvements in there. I'm excited to merge this after almost 8 months! 🎉 |
This is a very large change, as it not only removes Temporal.Calendar and Temporal.TimeZone, but also tries to eliminate any extra complexity due to no longer having to deal with user code calls for calendar and time zone calculations. Some of the things that are removed or simplified include: - No more Calendar Method Records and Time Zone Method Records - In many places, no need to pass around the user's original options bag - In many places, no need to pass around the user's original PlainDate or Instant; use epoch nanoseconds, ISO Date Records, and ISO Date-Time Records instead - No more copying the own properties of options bags - Most of the calendar and time zone operations are now infallible - The set of extra calendar fields that used to be returned by Temporal.Calendar.prototype.fields() is now static; so no need to have the complicated PrepareTemporalFields operation that returns a null- prototype object with own data properties that correspond to arbitrary user fields. Dates in calendar space can be represented by a Calendar Fields Record with known fields. - Much of the special-casing to avoid user calls that was added in #2519 and similar PRs is now unobservable and is removed. Closes: #2836 Closes: #2853 Closes: #2854
This is a very large change, as it not only removes Temporal.Calendar and Temporal.TimeZone, but also tries to eliminate any extra complexity due to no longer having to deal with user code calls for calendar and time zone calculations. Some of the things that are removed or simplified include: - No more Calendar Method Records and Time Zone Method Records - In many places, no need to pass around the user's original options bag - In many places, no need to pass around the user's original PlainDate or Instant; use epoch nanoseconds, ISO Date Records, and ISO Date-Time Records instead - No more copying the own properties of options bags - Most of the calendar and time zone operations are now infallible - The set of extra calendar fields that used to be returned by Temporal.Calendar.prototype.fields() is now static; so no need to have the complicated PrepareTemporalFields operation that returns a null- prototype object with own data properties that correspond to arbitrary user fields. Dates in calendar space can be represented by a Calendar Fields Record with known fields. - Much of the special-casing to avoid user calls that was added in #2519 and similar PRs is now unobservable and is removed. Closes: #2836 Closes: #2853 Closes: #2854
This is a very large change, as it not only removes Temporal.Calendar and Temporal.TimeZone, but also tries to eliminate any extra complexity due to no longer having to deal with user code calls for calendar and time zone calculations. Some of the things that are removed or simplified include: - No more Calendar Method Records and Time Zone Method Records - In many places, no need to pass around the user's original options bag - In many places, no need to pass around the user's original PlainDate or Instant; use epoch nanoseconds, ISO Date Records, and ISO Date-Time Records instead - No more copying the own properties of options bags - Most of the calendar and time zone operations are now infallible - The set of extra calendar fields that used to be returned by Temporal.Calendar.prototype.fields() is now static; so no need to have the complicated PrepareTemporalFields operation that returns a null- prototype object with own data properties that correspond to arbitrary user fields. Dates in calendar space can be represented by a Calendar Fields Record with known fields. - Much of the special-casing to avoid user calls that was added in #2519 and similar PRs is now unobservable and is removed. Closes: #2836 Closes: #2853 Closes: #2854
This is an audit of the whole proposal for opportunities where we can reduce the number of calls we make into user code.
Very large, recommend reviewing commit by commit.