Browse Source

LibJS: Fast-path ToTemporalCalendar when the argument is a Calendar

This is a normative change in the Temporal spec.

See: https://github.com/tc39/proposal-temporal/commit/2a43b39
Luke Wilde 2 years ago
parent
commit
8c3512d6ce

+ 11 - 4
Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp

@@ -369,7 +369,14 @@ ThrowCompletionOr<Object*> to_temporal_calendar(VM& vm, Value temporal_calendar_
     // 1. If Type(temporalCalendarLike) is Object, then
     if (temporal_calendar_like.is_object()) {
         auto& temporal_calendar_like_object = temporal_calendar_like.as_object();
-        // a. If temporalCalendarLike has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalTime]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+
+        // a. If temporalCalendarLike has an [[InitializedTemporalCalendar]] internal slot, then
+        if (is<Calendar>(temporal_calendar_like_object)) {
+            // i. Return temporalCalendarLike.
+            return &temporal_calendar_like_object;
+        }
+
+        // b. If temporalCalendarLike has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalTime]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
         // i. Return temporalCalendarLike.[[Calendar]].
         if (is<PlainDate>(temporal_calendar_like_object))
             return &static_cast<PlainDate&>(temporal_calendar_like_object).calendar();
@@ -384,14 +391,14 @@ ThrowCompletionOr<Object*> to_temporal_calendar(VM& vm, Value temporal_calendar_
         if (is<ZonedDateTime>(temporal_calendar_like_object))
             return &static_cast<ZonedDateTime&>(temporal_calendar_like_object).calendar();
 
-        // b. If ? HasProperty(temporalCalendarLike, "calendar") is false, return temporalCalendarLike.
+        // c. If ? HasProperty(temporalCalendarLike, "calendar") is false, return temporalCalendarLike.
         if (!TRY(temporal_calendar_like_object.has_property(vm.names.calendar)))
             return &temporal_calendar_like_object;
 
-        // c. Set temporalCalendarLike to ? Get(temporalCalendarLike, "calendar").
+        // d. Set temporalCalendarLike to ? Get(temporalCalendarLike, "calendar").
         temporal_calendar_like = TRY(temporal_calendar_like_object.get(vm.names.calendar));
 
-        // d. If Type(temporalCalendarLike) is Object and ? HasProperty(temporalCalendarLike, "calendar") is false, return temporalCalendarLike.
+        // e. If Type(temporalCalendarLike) is Object and ? HasProperty(temporalCalendarLike, "calendar") is false, return temporalCalendarLike.
         if (temporal_calendar_like.is_object() && !TRY(temporal_calendar_like.as_object().has_property(vm.names.calendar)))
             return &temporal_calendar_like.as_object();
     }

+ 18 - 0
Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.from.js

@@ -24,4 +24,22 @@ describe("normal behavior", () => {
         expect(Temporal.Calendar.from("iso8601").id).toBe("iso8601");
         expect(Temporal.Calendar.from("2021-07-06[u-ca=iso8601]").id).toBe("iso8601");
     });
+
+    test("ToTemporalCalendar fast path returns if it is passed a Temporal.Calendar instance", () => {
+        // This is obseravble via there being no property lookups (avoiding a "calendar" property lookup in this case)
+        let madeObservableHasPropertyLookup = false;
+        class Calendar extends Temporal.Calendar {
+            constructor() {
+                super("iso8601");
+            }
+
+            get calendar() {
+                madeObservableHasPropertyLookup = true;
+                return this;
+            }
+        }
+        const calendar = new Calendar();
+        Temporal.Calendar.from(calendar);
+        expect(madeObservableHasPropertyLookup).toBeFalse();
+    });
 });