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

delegate review: why are "Temporal-like" objects supported at all? #1428

Closed
ljharb opened this issue Mar 7, 2021 · 10 comments · Fixed by #1484
Closed

delegate review: why are "Temporal-like" objects supported at all? #1428

ljharb opened this issue Mar 7, 2021 · 10 comments · Fixed by #1484

Comments

@ljharb
Copy link
Member

ljharb commented Mar 7, 2021

(To start, this issue is not about TimeZone and Calendar, but the other Temporal types)

#1419 (comment) implies that .from methods are meant to support the following inputs:

  1. actual Temporal instances that have sufficient information to be able to construct the relevant Temporal instance
  2. strings that can be deserialized to the relevant Temporal instance
  3. arbitrary "Temporal-like" objects that aren't temporal instances, but have sufficient properties to be able to construct the relevant Temporal instance

The current spec seems to treat the first case as a subset of the third case - ie, it looks up object properties, and assumes that a Temporal-like object and a Temporal object have the same property names.

For actual Temporal instances, why would we not prefer looking things up from internal slots, so as to minimize observable lookups and calls into user code?

@littledan
Copy link
Member

littledan commented Mar 8, 2021

It's important to support construction of Temporal instances from options bags of named arguments, so this is why it is important to support case 3.

For the question of when internal slots vs properties should be accessed, we had some pretty extensive discussion on this topic in #231 . I became convinced, in that thread, that being careful to use internal slots whenever possible adds much more complexity than is saved.

One way to think about .from is that it's really for cases 2 and 3, and you have explicit projection operators, e.g., Temporal.ZonedDateTime.prototype.toInstant to reliably do what you are describing as case 1. Case 1 just "happens to work" on from, in this perspective.

@ljharb
Copy link
Member Author

ljharb commented Mar 8, 2021

That makes sense, but I’d generally expect a fast unobservable path for actual instances.#231 seems to focus on with a bit more than from towards the end there; is there a specific comment that would help convince me?

@littledan
Copy link
Member

@ljharb For me, the reason is that, if you think about all of the different Temporal types that have a sense of, say, what the "day" is, and how this is calculated (given the complexity of calendars), it ends up adding significant additional complexity to make a sort of "fastpath" for these sorts of cases. (The complexity is more clear if you think through how the spec would be written, and implementations would end up looking similar.)

@ljharb
Copy link
Member Author

ljharb commented Mar 9, 2021

The builtin temporal types could call into the intrinsics, for example, instead of doing lookups from an instance.

@ptomato
Copy link
Collaborator

ptomato commented Mar 9, 2021

I think it's fine to do these fast paths. There are the following ones:

  • PlainDate → PlainDateTime (assuming we apply the "time defaults to midnight" consistently here as we do elsewhere)
  • PlainDateTime → PlainDate
  • PlainDateTime → PlainTime
  • ZonedDateTime → Instant
  • ZonedDateTime → TimeZone
  • PlainDate, PlainDateTime, PlainMonthDay, PlainYearMonth, ZonedDateTime → Calendar

I might be wrong but I don't expect this will add too much implementation complexity. I expect this is a question of adding a few extra steps to operations like ToTemporalDate, something like:

  1. If item has an [[InitializedTemporalPlainDateTime]] internal slot, then
    1. Return ? CreateTemporalDate(item.[[ISOYear]], item.[[ISOMonth]], item.[[ISODay]], item.[[Calendar]]).

I'm not sure why we decided not to do these before but it was probably for simplicity and may have been before getters actually triggered all these observable Calendar calls.

@justingrant
Copy link
Collaborator

I think it's fine to do these fast paths. There are the following ones:

  • PlainDate → PlainDateTime (assuming we apply the "time defaults to midnight" consistently here as we do elsewhere)
  • PlainDateTime → PlainDate
  • PlainDateTime → PlainTime
  • ZonedDateTime → Instant
  • ZonedDateTime → TimeZone
  • PlainDate, PlainDateTime, PlainMonthDay, PlainYearMonth, ZonedDateTime → Calendar

Is the rule that if no calls to the calendar and/or time zone are needed, then we use a fast path, otherwise we do observable reads of properties? Or does the fast path apply even in cases where the calendar and/or time zone needs to be called in order to calculate the result?

If the former, then what about these?

  • PlainDate, PlainDateTime → PlainYearMonth
  • PlainDate, PlainDateTime → PlainMonthDay (or is this exempt because it must go through the calendar to normalize the ISO year?)

If the latter, then these too?

  • ZonedDateTime → PlainMonthDay, PlainYearMonth, PlainTime, PlainDateTime, PlainDate

@ptomato ptomato added this to the Stage 3 Conditional milestone Mar 19, 2021
@ptomato
Copy link
Collaborator

ptomato commented Mar 20, 2021

Is the rule that if no calls to the calendar and/or time zone are needed, then we use a fast path, otherwise we do observable reads of properties? Or does the fast path apply even in cases where the calendar and/or time zone needs to be called in order to calculate the result?

I had the former in mind, but (see below) I'm not sure there are any more fast paths possible if we were to say the latter.

If the former, then what about these?

* PlainDate, PlainDateTime → PlainYearMonth

* PlainDate, PlainDateTime → PlainMonthDay (or is this exempt because it must go through the calendar to normalize the ISO year?)

I didn't include these because they both must go through the calendar (PlainYearMonth must normalize the ISO day, and PlainMonthDay must normalize the ISO year.)

If the latter, then these too?

* ZonedDateTime → PlainMonthDay, PlainYearMonth, PlainTime, PlainDateTime, PlainDate

I think these are already "fast-pathed" as much as possible. You get a PlainDateTime by going through the time zone. In the case of ZonedDateTime → PlainDateTime, that object is returned directly. In the case of PlainDate and PlainTime, the slots are read. In the case of PlainMonthDay and PlainYearMonth, you still have to go through the calendar as above.

@justingrant
Copy link
Collaborator

justingrant commented Mar 20, 2021

I didn't include these because they both must go through the calendar (PlainYearMonth must normalize the ISO day, and PlainMonthDay must normalize the ISO year.)

Does it matter that for ISO or built-in non-ISO calendars, the ISO day is always 1?

And does it matter that for ISO or built-in calendars except Hebrew and Chinese/Dangi, the ISO year is always a constant value?

In other words, is there some possible fast path for built-in calendars only that's possible by avoiding observable calls?

I think these are already "fast-pathed" as much as possible. You get a PlainDateTime by going through the time zone. In the case of ZonedDateTime → PlainDateTime, that object is returned directly. In the case of PlainDate and PlainTime, the slots are read. In the case of PlainMonthDay and PlainYearMonth, you still have to go through the calendar as above.

Not sure I understand. There are two ways to get Plain* values from a ZDT:

  1. observably call each date and time getter, retrieving property values one by one
  2. fetch the EPOCHNANOSECONDS,TIME_ZONE, and CALENDAR slots, and call TimeZone.prototype.getPlainDateTimeFor to get the result (downscaling to date or time as needed).

Isn't (2) best from a performance perspective and for ease for implementations to optimize? Or are you saying that we're already doing (2) so that's why it's not on your list?

@ptomato
Copy link
Collaborator

ptomato commented Mar 22, 2021

Or are you saying that we're already doing (2) so that's why it's not on your list?

Exactly, we're already doing it. (see, for example https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.toplaindate)

Does it matter that for ISO or built-in non-ISO calendars, the ISO day is always 1?

And does it matter that for ISO or built-in calendars except Hebrew and Chinese/Dangi, the ISO year is always a constant value?

In other words, is there some possible fast path for built-in calendars only that's possible by avoiding observable calls?

Maybe for built-in calendars you could have a non-observable path for ISO y/m/d to calendar PlainYearMonth or PlainMonthDay, but I'm not sold on this idea because it would duplicate calendar logic (choosing a reference year or reference day) outside of the calendar. To me, this crosses the boundary mentioned in #1428 (comment).

@ptomato ptomato self-assigned this Apr 6, 2021
@ptomato
Copy link
Collaborator

ptomato commented Apr 12, 2021

Following up on this after having written a bunch of test262 tests for it...

Or are you saying that we're already doing (2) so that's why it's not on your list?

Exactly, we're already doing it. (see, for example https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.toplaindate)

I was only partially correct about this. We are doing it this way in places like Temporal.ZonedDateTime.prototype.toPlainDate(), but not in the ToTemporalDate, ToTemporalDateTime etc. abstract operations, and we should additionally be doing it there. I'll make sure this happens.

ptomato added a commit that referenced this issue Apr 13, 2021
If passing a Temporal object with a [[Calendar]] internal slot where a
calendar is expected, then read that slot instead of doing a Get on the
"calendar" property.
(The Get operation was also not consistently done throughout the existing
spec text, so fix that as well. This means the CalendarFrom operation
becomes redundant, so remove it.)

See: #1428
ptomato added a commit that referenced this issue Apr 13, 2021
If passing a Temporal.ZonedDateTime where a Temporal.Instant is expected,
then create a Temporal.Instant directly from the ZonedDateTime's
[[Nanoseconds]] internal slot.
Previously, the ZonedDateTime's toString() method would have been called,
and the result would have been parsed into an Instant.

See: #1428
ptomato added a commit that referenced this issue Apr 13, 2021
If passing a Temporal.PlainDateTime where a Temporal.PlainDate is
expected, then create a Temporal.PlainDate directly from the
PlainDateTime's [[ISOYear]], [[ISOMonth]], and [[ISODay]] internal slots.
Previously, the PlainDateTime's calendar, year, month, monthCode, and day
getters would have been called.

See: #1428
ptomato added a commit that referenced this issue Apr 13, 2021
If passing a Temporal.PlainDate where a Temporal.PlainDateTime is
expected, then create a Temporal.PlainDateTime directly from the
PlainDate's [[ISOYear]], [[ISOMonth]], and [[ISODay]] internal slots, and
assume midnight as the time, just as if a property bag with year,
month/monthCode, and day properties had been passed.
Previously, the PlainDate's calendar, year, month, monthCode, and day
getters would have been called, and the time properties would have been
accessed as well.

See: #1428
ptomato added a commit that referenced this issue Apr 13, 2021
If passing a Temporal.PlainDateTime where a Temporal.PlainTime is
expected, then create a Temporal.PlainTime directly from the
PlainDateTime's [[ISOHour]], [[ISOMinute]], [[ISOSecond]],
[[ISOMillisecond]], [[ISOMicrosecond]], and [[ISONanosecond]] internal
slots.
Previously, the PlainDateTime's hour, minute, second, millisecond,
microsecond, nanosecond, and calendar getters would have been called.

See: #1428
ptomato added a commit that referenced this issue Apr 13, 2021
If passing a Temporal.ZonedDateTime (that is, a Temporal object with a
[[TimeZone]] internal slot) where a Temporal.TimeZone is expected, then
read that slot instead of doing a Get on the "timeZone" property.

The Get operation was also not consistently done throughout the existing
spec text, so fix that as well. This means the TimeZoneFrom operation
becomes redundant, so remove it. Additionally, the check for the
"timeZone" property on plain objects was not implemented according to the
consensus in
#925 (comment)
and this change fixes that as well.

See: #1428
ptomato added a commit that referenced this issue Apr 13, 2021
The value of a relativeTo property in a property bag is already allowed to
be either a Temporal.PlainDateTime or Temporal.ZonedDateTime. If passing a
Temporal.PlainDate, then create a Temporal.PlainDateTime from its slots as
we do in ToTemporalDateTime.

See: #1428
ptomato added a commit that referenced this issue Apr 13, 2021
There are a few places where the `calendar` property of a property bag is
read. If the property bag is actually a Temporal object with a
[[Calendar]] internal slot, then read this slot instead.

See: #1428
ptomato added a commit that referenced this issue Apr 13, 2021
…Time

If passing a Temporal.ZonedDateTime where a Temporal.PlainDate,
Temporal.PlainTime, or Temporal.PlainDateTime is expected, then first call
the built-in TimeZone.getPlainDateTimeFor() method to obtain a
Temporal.PlainDateTime object and proceed accordingly.
Previously, the ZonedDateTime's getters would have been called,
potentially calling the getPlainDateTimeFor() method multiple times; very
inefficient.

See: #1428
ptomato added a commit that referenced this issue Apr 13, 2021
All of the with() methods check that the given object doesn't have a
`calendar` or `timeZone` property. Short-circuit these checks by first
checking if it's a Temporal object with a [[Calendar]] or [[TimeZone]]
internal slot, so that no Gets are performed in that case.

See: #1428
ptomato added a commit that referenced this issue Apr 13, 2021
Make sure it is consistent whether a particular Calendar method can be
called with a Temporal.PlainYearMonth or Temporal.PlainMonthDay without
triggering a conversion. (They can all be called with a
Temporal.PlainDate.)

See: #1428
ptomato added a commit that referenced this issue Apr 13, 2021
If passing a Temporal object with a [[Calendar]] internal slot where a
calendar is expected, then read that slot instead of doing a Get on the
"calendar" property.
(The Get operation was also not consistently done throughout the existing
spec text, so fix that as well. This means the CalendarFrom operation
becomes redundant, so remove it.)

See: #1428
ptomato added a commit that referenced this issue Apr 13, 2021
If passing a Temporal.ZonedDateTime where a Temporal.Instant is expected,
then create a Temporal.Instant directly from the ZonedDateTime's
[[Nanoseconds]] internal slot.
Previously, the ZonedDateTime's toString() method would have been called,
and the result would have been parsed into an Instant.

See: #1428
ptomato added a commit that referenced this issue Apr 13, 2021
If passing a Temporal.PlainDateTime where a Temporal.PlainDate is
expected, then create a Temporal.PlainDate directly from the
PlainDateTime's [[ISOYear]], [[ISOMonth]], and [[ISODay]] internal slots.
Previously, the PlainDateTime's calendar, year, month, monthCode, and day
getters would have been called.

See: #1428
ptomato added a commit that referenced this issue Apr 13, 2021
All of the with() methods check that the given object doesn't have a
`calendar` or `timeZone` property. Short-circuit these checks by first
checking if it's a Temporal object with a [[Calendar]] or [[TimeZone]]
internal slot, so that no Gets are performed in that case.

See: #1428
ptomato added a commit that referenced this issue Apr 13, 2021
Make sure it is consistent whether a particular Calendar method can be
called with a Temporal.PlainYearMonth or Temporal.PlainMonthDay without
triggering a conversion. (They can all be called with a
Temporal.PlainDate.)

See: #1428
ptomato added a commit that referenced this issue Apr 14, 2021
Now that we have a fast-path conversion from PlainDateTime to PlainDate,
it's no longer necessary to check for an [[ISOYear]] internal slot. Make
sure it is consistent whether a particular Calendar method can be called
with a Temporal.PlainYearMonth or Temporal.PlainMonthDay without
triggering a conversion, if appropriate.

The policy is that these Calendar methods can all be called with a
PlainDate, and additionally some of them can be called with a
PlainYearMonth and/or PlainMonthDay. Anything else gets passed through
ToTemporalDate, which includes the fast path for PlainDateTime.

See: #1428
ptomato added a commit that referenced this issue Apr 14, 2021
Now that we have a fast-path conversion from PlainDateTime to PlainDate,
it's no longer necessary to check for an [[ISOYear]] internal slot. Make
sure it is consistent whether a particular Calendar method can be called
with a Temporal.PlainYearMonth or Temporal.PlainMonthDay without
triggering a conversion, if appropriate.

The policy is that these Calendar methods can all be called with a
PlainDate, and additionally some of them can be called with a
PlainYearMonth and/or PlainMonthDay. Anything else gets passed through
ToTemporalDate, which includes the fast path for PlainDateTime.

See: #1428
ptomato added a commit that referenced this issue Apr 15, 2021
If passing a Temporal.ZonedDateTime (that is, a Temporal object with a
[[TimeZone]] internal slot) where a Temporal.TimeZone is expected, then
read that slot instead of doing a Get on the "timeZone" property.

The Get operation was also not consistently done throughout the existing
spec text, so fix that as well. This means the TimeZoneFrom operation
becomes redundant, so remove it. Additionally, the check for the
"timeZone" property on plain objects was not implemented according to the
consensus in
#925 (comment)
and this change fixes that as well.

See: #1428
ptomato added a commit that referenced this issue Apr 15, 2021
The value of a relativeTo property in a property bag is already allowed to
be either a Temporal.PlainDateTime or Temporal.ZonedDateTime. If passing a
Temporal.PlainDate, then create a Temporal.PlainDateTime from its slots as
we do in ToTemporalDateTime.

See: #1428
ptomato added a commit that referenced this issue Apr 15, 2021
There are a few places where the `calendar` property of a property bag is
read. If the property bag is actually a Temporal object with a
[[Calendar]] internal slot, then read this slot instead.

See: #1428
ptomato added a commit that referenced this issue Apr 15, 2021
…Time

If passing a Temporal.ZonedDateTime where a Temporal.PlainDate,
Temporal.PlainTime, or Temporal.PlainDateTime is expected, then first call
the built-in TimeZone.getPlainDateTimeFor() method to obtain a
Temporal.PlainDateTime object and proceed accordingly.
Previously, the ZonedDateTime's getters would have been called,
potentially calling the getPlainDateTimeFor() method multiple times; very
inefficient.

See: #1428
ptomato added a commit that referenced this issue Apr 15, 2021
All of the with() methods check that the given object doesn't have a
`calendar` or `timeZone` property. Short-circuit these checks by first
checking if it's a Temporal object with a [[Calendar]] or [[TimeZone]]
internal slot, so that no Gets are performed in that case.

See: #1428
ptomato added a commit that referenced this issue Apr 15, 2021
Now that we have a fast-path conversion from PlainDateTime to PlainDate,
it's no longer necessary to check for an [[ISOYear]] internal slot. Make
sure it is consistent whether a particular Calendar method can be called
with a Temporal.PlainYearMonth or Temporal.PlainMonthDay without
triggering a conversion, if appropriate.

The policy is that these Calendar methods can all be called with a
PlainDate, and additionally some of them can be called with a
PlainYearMonth and/or PlainMonthDay. Anything else gets passed through
ToTemporalDate, which includes the fast path for PlainDateTime.

See: #1428
ptomato added a commit that referenced this issue Apr 15, 2021
The constructors of PlainDate, PlainDateTime, PlainMonthDay,
PlainYearMonth, and ZonedDateTime call ToTemporalCalendar on the calendar
argument, and the constructor of ZonedDateTime additionally calls
ToTemporalTimeZone on its timeZone argument. Now that these operations
include an observable HasProperty operation, we do not want to call them
more than once on the same calendar or time zone object.

Therefore we add a private Symbol ES.PrivateCreateMethod, which hides
internal static methods on these types, which create an instance without
any observable validation of the arguments.

The spec text already works like this, with abstract operations such as
CreateTemporalZonedDateTime and friends that do not call
ToTemporalCalendar or ToTemporalTimeZone. So this is not a normative
change; it's a compliance bug in the polyfill. It is required for the
test262 tests in 19cd26f to pass, which observe HasProperty(`timeZone`)
operations.

See: #1428
ptomato added a commit that referenced this issue Apr 16, 2021
All of the with() methods check that the given object doesn't have a
`calendar` or `timeZone` property. Short-circuit these checks by first
checking if it's a Temporal object with a [[Calendar]] or [[TimeZone]]
internal slot, so that no Gets are performed in that case.

See: #1428
ptomato added a commit that referenced this issue Apr 16, 2021
Now that we have a fast-path conversion from PlainDateTime to PlainDate,
it's no longer necessary to check for an [[ISOYear]] internal slot. Make
sure it is consistent whether a particular Calendar method can be called
with a Temporal.PlainYearMonth or Temporal.PlainMonthDay without
triggering a conversion, if appropriate.

The policy is that these Calendar methods can all be called with a
PlainDate, and additionally some of them can be called with a
PlainYearMonth and/or PlainMonthDay. Anything else gets passed through
ToTemporalDate, which includes the fast path for PlainDateTime.

See: #1428
ptomato added a commit that referenced this issue Apr 16, 2021
The constructors of PlainDate, PlainDateTime, PlainMonthDay,
PlainYearMonth, and ZonedDateTime call ToTemporalCalendar on the calendar
argument, and the constructor of ZonedDateTime additionally calls
ToTemporalTimeZone on its timeZone argument. Now that these operations
include an observable HasProperty operation, we do not want to call them
more than once on the same calendar or time zone object.

Therefore we add CreateTemporalDate etc. which create an instance without
any observable validation of the arguments.

The spec text already works like this, with abstract operations such as
CreateTemporalZonedDateTime and friends that do not call
ToTemporalCalendar or ToTemporalTimeZone. So this is not a normative
change; it's a compliance bug in the polyfill. It is required for the
test262 tests in 19cd26f to pass, which observe HasProperty(`timeZone`)
operations.

See: #1428
ptomato added a commit that referenced this issue Apr 16, 2021
If passing a Temporal object with a [[Calendar]] internal slot where a
calendar is expected, then read that slot instead of doing a Get on the
"calendar" property.
(The Get operation was also not consistently done throughout the existing
spec text, so fix that as well. This means the CalendarFrom operation
becomes redundant, so remove it.)

See: #1428
ptomato added a commit that referenced this issue Apr 16, 2021
If passing a Temporal.ZonedDateTime where a Temporal.Instant is expected,
then create a Temporal.Instant directly from the ZonedDateTime's
[[Nanoseconds]] internal slot.
Previously, the ZonedDateTime's toString() method would have been called,
and the result would have been parsed into an Instant.

See: #1428
ptomato added a commit that referenced this issue Apr 16, 2021
If passing a Temporal.PlainDateTime where a Temporal.PlainDate is
expected, then create a Temporal.PlainDate directly from the
PlainDateTime's [[ISOYear]], [[ISOMonth]], and [[ISODay]] internal slots.
Previously, the PlainDateTime's calendar, year, month, monthCode, and day
getters would have been called.

See: #1428
ptomato added a commit that referenced this issue Apr 16, 2021
If passing a Temporal.PlainDate where a Temporal.PlainDateTime is
expected, then create a Temporal.PlainDateTime directly from the
PlainDate's [[ISOYear]], [[ISOMonth]], and [[ISODay]] internal slots, and
assume midnight as the time, just as if a property bag with year,
month/monthCode, and day properties had been passed.
Previously, the PlainDate's calendar, year, month, monthCode, and day
getters would have been called, and the time properties would have been
accessed as well.

See: #1428
ptomato added a commit that referenced this issue Apr 16, 2021
If passing a Temporal.PlainDateTime where a Temporal.PlainTime is
expected, then create a Temporal.PlainTime directly from the
PlainDateTime's [[ISOHour]], [[ISOMinute]], [[ISOSecond]],
[[ISOMillisecond]], [[ISOMicrosecond]], and [[ISONanosecond]] internal
slots.
Previously, the PlainDateTime's hour, minute, second, millisecond,
microsecond, nanosecond, and calendar getters would have been called.

See: #1428
ptomato added a commit that referenced this issue Apr 16, 2021
If passing a Temporal.ZonedDateTime (that is, a Temporal object with a
[[TimeZone]] internal slot) where a Temporal.TimeZone is expected, then
read that slot instead of doing a Get on the "timeZone" property.

The Get operation was also not consistently done throughout the existing
spec text, so fix that as well. This means the TimeZoneFrom operation
becomes redundant, so remove it. Additionally, the check for the
"timeZone" property on plain objects was not implemented according to the
consensus in
#925 (comment)
and this change fixes that as well.

See: #1428
ptomato added a commit that referenced this issue Apr 16, 2021
The value of a relativeTo property in a property bag is already allowed to
be either a Temporal.PlainDateTime or Temporal.ZonedDateTime. If passing a
Temporal.PlainDate, then create a Temporal.PlainDateTime from its slots as
we do in ToTemporalDateTime.

See: #1428
ptomato added a commit that referenced this issue Apr 16, 2021
There are a few places where the `calendar` property of a property bag is
read. If the property bag is actually a Temporal object with a
[[Calendar]] internal slot, then read this slot instead.

See: #1428
ptomato added a commit that referenced this issue Apr 16, 2021
…Time

If passing a Temporal.ZonedDateTime where a Temporal.PlainDate,
Temporal.PlainTime, or Temporal.PlainDateTime is expected, then first call
the built-in TimeZone.getPlainDateTimeFor() method to obtain a
Temporal.PlainDateTime object and proceed accordingly.
Previously, the ZonedDateTime's getters would have been called,
potentially calling the getPlainDateTimeFor() method multiple times; very
inefficient.

See: #1428
ptomato added a commit that referenced this issue Apr 16, 2021
All of the with() methods check that the given object doesn't have a
`calendar` or `timeZone` property. Short-circuit these checks by first
checking if it's a Temporal object with a [[Calendar]] or [[TimeZone]]
internal slot, so that no Gets are performed in that case.

See: #1428
ptomato added a commit that referenced this issue Apr 16, 2021
Now that we have a fast-path conversion from PlainDateTime to PlainDate,
it's no longer necessary to check for an [[ISOYear]] internal slot. Make
sure it is consistent whether a particular Calendar method can be called
with a Temporal.PlainYearMonth or Temporal.PlainMonthDay without
triggering a conversion, if appropriate.

The policy is that these Calendar methods can all be called with a
PlainDate, and additionally some of them can be called with a
PlainYearMonth and/or PlainMonthDay. Anything else gets passed through
ToTemporalDate, which includes the fast path for PlainDateTime.

See: #1428
ptomato added a commit that referenced this issue Apr 16, 2021
The constructors of PlainDate, PlainDateTime, PlainMonthDay,
PlainYearMonth, and ZonedDateTime call ToTemporalCalendar on the calendar
argument, and the constructor of ZonedDateTime additionally calls
ToTemporalTimeZone on its timeZone argument. Now that these operations
include an observable HasProperty operation, we do not want to call them
more than once on the same calendar or time zone object.

Therefore we add CreateTemporalDate etc. which create an instance without
any observable validation of the arguments.

The spec text already works like this, with abstract operations such as
CreateTemporalZonedDateTime and friends that do not call
ToTemporalCalendar or ToTemporalTimeZone. So this is not a normative
change; it's a compliance bug in the polyfill. It is required for the
test262 tests in 19cd26f to pass, which observe HasProperty(`timeZone`)
operations.

See: #1428
@ptomato ptomato mentioned this issue Apr 19, 2021
44 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants