From 35c9e324b4248c8953b151cbb89497d5a5afb2ea Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Sun, 16 Oct 2022 00:43:13 +0100 Subject: [PATCH] LibJS: Add fast path TimeZone conversion to PlainDate#toZonedDateTime This is a normative chane in the Temporal spec. See: https://github.com/tc39/proposal-temporal/commit/fcab1af --- .../Runtime/Temporal/PlainDatePrototype.cpp | 34 ++++++++++++------- .../PlainDate.prototype.toZonedDateTime.js | 20 +++++++++++ 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.cpp index e2cbd780bf..2222b1eef1 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.cpp @@ -525,23 +525,33 @@ JS_DEFINE_NATIVE_FUNCTION(PlainDatePrototype::to_zoned_date_time) // 3. If Type(item) is Object, then if (item.is_object()) { - // a. Let timeZoneLike be ? Get(item, "timeZone"). - auto time_zone_like = TRY(item.as_object().get(vm.names.timeZone)); - - // b. If timeZoneLike is undefined, then - if (time_zone_like.is_undefined()) { - // i. Let timeZone be ? ToTemporalTimeZone(item). - time_zone = TRY(to_temporal_time_zone(vm, item)); + // a. If item has an [[InitializedTemporalTimeZone]] internal slot, then + if (is(item.as_object())) { + // i. Let timeZone be item. + time_zone = &item.as_object(); // ii. Let temporalTime be undefined. } - // c. Else, + // b. Else, else { - // i. Let timeZone be ? ToTemporalTimeZone(timeZoneLike). - time_zone = TRY(to_temporal_time_zone(vm, time_zone_like)); + // i. Let timeZoneLike be ? Get(item, "timeZone"). + auto time_zone_like = TRY(item.as_object().get(vm.names.timeZone)); - // ii. Let temporalTime be ? Get(item, "plainTime"). - temporal_time_value = TRY(item.as_object().get(vm.names.plainTime)); + // ii. If timeZoneLike is undefined, then + if (time_zone_like.is_undefined()) { + // 1. Let timeZone be ? ToTemporalTimeZone(item). + time_zone = TRY(to_temporal_time_zone(vm, item)); + + // 2. Let temporalTime be undefined. + } + // iii. Else, + else { + // 1. Let timeZone be ? ToTemporalTimeZone(timeZoneLike). + time_zone = TRY(to_temporal_time_zone(vm, time_zone_like)); + + // 2. Let temporalTime be ? Get(item, "plainTime"). + temporal_time_value = TRY(item.as_object().get(vm.names.plainTime)); + } } } // 4. Else, diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.toZonedDateTime.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.toZonedDateTime.js index 9f3c7a8d8e..1d475faea5 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.toZonedDateTime.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.toZonedDateTime.js @@ -74,6 +74,26 @@ describe("correct behavior", () => { expect(zonedDateTime.calendar).toBe(plainDate.calendar); expect(zonedDateTime.timeZone.id).toBe("UTC"); }); + + test("time zone fast path returns if it is passed a Temporal.TimeZone instance", () => { + const plainDate = new Temporal.PlainDate(2021, 7, 6); + + // This is obseravble via there being no property lookups (avoiding a "timeZone" property lookup in this case) + let madeObservableHasPropertyLookup = false; + class TimeZone extends Temporal.TimeZone { + constructor() { + super("UTC"); + } + + get timeZone() { + madeObservableHasPropertyLookup = true; + return this; + } + } + const timeZone = new TimeZone(); + plainDate.toZonedDateTime(timeZone); + expect(madeObservableHasPropertyLookup).toBeFalse(); + }); }); describe("errors", () => {