From a3ad12d5b435fe324a33de68df52deb3286e82c3 Mon Sep 17 00:00:00 2001 From: Zeno Leonardi Date: Fri, 20 Feb 2026 15:40:00 +0100 Subject: [PATCH 1/5] setup plain time --- nova_vm/src/ecmascript/builtins/temporal.rs | 2 ++ nova_vm/src/ecmascript/builtins/temporal/plain_time.rs | 8 +++++--- .../src/ecmascript/builtins/temporal/plain_time/data.rs | 8 ++++---- .../temporal/plain_time/plain_time_constructor.rs | 9 ++------- nova_vm/src/heap/heap_bits.rs | 1 + 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/nova_vm/src/ecmascript/builtins/temporal.rs b/nova_vm/src/ecmascript/builtins/temporal.rs index 4b088e3de..5cdda5170 100644 --- a/nova_vm/src/ecmascript/builtins/temporal.rs +++ b/nova_vm/src/ecmascript/builtins/temporal.rs @@ -5,12 +5,14 @@ mod duration; mod error; mod instant; +mod plain_time; mod options; mod plain_time; pub use duration::*; pub(crate) use error::*; pub use instant::*; +pub use plain_time::*; pub(crate) use options::*; pub use plain_time::*; diff --git a/nova_vm/src/ecmascript/builtins/temporal/plain_time.rs b/nova_vm/src/ecmascript/builtins/temporal/plain_time.rs index be1ce4ae3..0f52a77ec 100644 --- a/nova_vm/src/ecmascript/builtins/temporal/plain_time.rs +++ b/nova_vm/src/ecmascript/builtins/temporal/plain_time.rs @@ -10,6 +10,8 @@ pub(crate) use data::*; pub(crate) use plain_time_constructor::*; pub(crate) use plain_time_prototype::*; +use temporal_rs::options::{Unit, UnitGroup}; + use crate::{ ecmascript::{ Agent, InternalMethods, InternalSlots, OrdinaryObject, ProtoIntrinsics, object_handle, @@ -29,12 +31,12 @@ arena_vec_access!( TemporalPlainTime, 'a, PlainTimeRecord, - plain_times + plain_time ); impl TemporalPlainTime<'_> { - pub(crate) fn _inner_plain_time(self, agent: &Agent) -> &temporal_rs::PlainTime { - &self.unbind().get(agent)._plain_time + pub(crate) fn inner_plain_time(self, agent: &Agent) -> &temporal_rs::PlainTime { + &self.unbind().get(agent).plain_time } } diff --git a/nova_vm/src/ecmascript/builtins/temporal/plain_time/data.rs b/nova_vm/src/ecmascript/builtins/temporal/plain_time/data.rs index 396fb9d0c..d7e3751e9 100644 --- a/nova_vm/src/ecmascript/builtins/temporal/plain_time/data.rs +++ b/nova_vm/src/ecmascript/builtins/temporal/plain_time/data.rs @@ -11,14 +11,14 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub struct PlainTimeRecord<'a> { pub(crate) object_index: Option>, - pub(crate) _plain_time: temporal_rs::PlainTime, + pub(crate) plain_time: temporal_rs::PlainTime, } impl PlainTimeRecord<'_> { pub fn default() -> Self { Self { object_index: None, - _plain_time: temporal_rs::PlainTime::try_new(0, 0, 0, 0, 0, 0).unwrap(), + plain_time: temporal_rs::PlainTime::try_new(0, 0, 0, 0, 0, 0).unwrap(), } } } @@ -30,7 +30,7 @@ impl HeapMarkAndSweep for PlainTimeRecord<'static> { fn mark_values(&self, queues: &mut WorkQueues) { let Self { object_index, - _plain_time: _, + plain_time: _, } = self; object_index.mark_values(queues); @@ -38,7 +38,7 @@ impl HeapMarkAndSweep for PlainTimeRecord<'static> { fn sweep_values(&mut self, compactions: &CompactionLists) { let Self { object_index, - _plain_time: _, + plain_time: _, } = self; object_index.sweep_values(compactions); diff --git a/nova_vm/src/ecmascript/builtins/temporal/plain_time/plain_time_constructor.rs b/nova_vm/src/ecmascript/builtins/temporal/plain_time/plain_time_constructor.rs index dfdaa712f..1f5d4654b 100644 --- a/nova_vm/src/ecmascript/builtins/temporal/plain_time/plain_time_constructor.rs +++ b/nova_vm/src/ecmascript/builtins/temporal/plain_time/plain_time_constructor.rs @@ -3,12 +3,7 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use crate::{ - ecmascript::{ - Agent, ArgumentsList, BUILTIN_STRING_MEMORY, Behaviour, Builtin, - BuiltinIntrinsicConstructor, JsResult, Object, Realm, String, Value, - builders::BuiltinFunctionBuilder, - }, - engine::{GcScope, NoGcScope}, + ecmascript::{BUILTIN_STRING_MEMORY, Behaviour, Builtin, BuiltinIntrinsicConstructor, String}, heap::IntrinsicConstructorIndexes, }; @@ -17,7 +12,7 @@ pub(crate) struct TemporalPlainTimeConstructor; impl Builtin for TemporalPlainTimeConstructor { const NAME: String<'static> = BUILTIN_STRING_MEMORY.PlainTime; - const LENGTH: u8 = 0; + const LENGTH: u8 = 1; const BEHAVIOUR: Behaviour = Behaviour::Constructor(TemporalPlainTimeConstructor::constructor); } impl BuiltinIntrinsicConstructor for TemporalPlainTimeConstructor { diff --git a/nova_vm/src/heap/heap_bits.rs b/nova_vm/src/heap/heap_bits.rs index 901c9dcbd..e55efd350 100644 --- a/nova_vm/src/heap/heap_bits.rs +++ b/nova_vm/src/heap/heap_bits.rs @@ -1714,6 +1714,7 @@ pub(crate) struct CompactionLists { pub(crate) weak_refs: CompactionList, #[cfg(feature = "weak-refs")] pub(crate) weak_sets: CompactionList, + pub(crate) plain_times: (), } impl CompactionLists { From 3f5c1f6c89cdb796e3c4ff1b2454c688ad09fe41 Mon Sep 17 00:00:00 2001 From: jesper Date: Sat, 21 Feb 2026 12:44:50 +0100 Subject: [PATCH 2/5] feat(ecmascript): PlainTime Foo Fix warnings --- nova_vm/src/ecmascript/builtins/temporal.rs | 2 -- nova_vm/src/ecmascript/builtins/temporal/plain_time.rs | 8 +++----- .../src/ecmascript/builtins/temporal/plain_time/data.rs | 8 ++++---- .../temporal/plain_time/plain_time_constructor.rs | 9 +++++++-- nova_vm/src/heap/heap_bits.rs | 1 - 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/nova_vm/src/ecmascript/builtins/temporal.rs b/nova_vm/src/ecmascript/builtins/temporal.rs index 5cdda5170..4b088e3de 100644 --- a/nova_vm/src/ecmascript/builtins/temporal.rs +++ b/nova_vm/src/ecmascript/builtins/temporal.rs @@ -5,14 +5,12 @@ mod duration; mod error; mod instant; -mod plain_time; mod options; mod plain_time; pub use duration::*; pub(crate) use error::*; pub use instant::*; -pub use plain_time::*; pub(crate) use options::*; pub use plain_time::*; diff --git a/nova_vm/src/ecmascript/builtins/temporal/plain_time.rs b/nova_vm/src/ecmascript/builtins/temporal/plain_time.rs index 0f52a77ec..be1ce4ae3 100644 --- a/nova_vm/src/ecmascript/builtins/temporal/plain_time.rs +++ b/nova_vm/src/ecmascript/builtins/temporal/plain_time.rs @@ -10,8 +10,6 @@ pub(crate) use data::*; pub(crate) use plain_time_constructor::*; pub(crate) use plain_time_prototype::*; -use temporal_rs::options::{Unit, UnitGroup}; - use crate::{ ecmascript::{ Agent, InternalMethods, InternalSlots, OrdinaryObject, ProtoIntrinsics, object_handle, @@ -31,12 +29,12 @@ arena_vec_access!( TemporalPlainTime, 'a, PlainTimeRecord, - plain_time + plain_times ); impl TemporalPlainTime<'_> { - pub(crate) fn inner_plain_time(self, agent: &Agent) -> &temporal_rs::PlainTime { - &self.unbind().get(agent).plain_time + pub(crate) fn _inner_plain_time(self, agent: &Agent) -> &temporal_rs::PlainTime { + &self.unbind().get(agent)._plain_time } } diff --git a/nova_vm/src/ecmascript/builtins/temporal/plain_time/data.rs b/nova_vm/src/ecmascript/builtins/temporal/plain_time/data.rs index d7e3751e9..396fb9d0c 100644 --- a/nova_vm/src/ecmascript/builtins/temporal/plain_time/data.rs +++ b/nova_vm/src/ecmascript/builtins/temporal/plain_time/data.rs @@ -11,14 +11,14 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub struct PlainTimeRecord<'a> { pub(crate) object_index: Option>, - pub(crate) plain_time: temporal_rs::PlainTime, + pub(crate) _plain_time: temporal_rs::PlainTime, } impl PlainTimeRecord<'_> { pub fn default() -> Self { Self { object_index: None, - plain_time: temporal_rs::PlainTime::try_new(0, 0, 0, 0, 0, 0).unwrap(), + _plain_time: temporal_rs::PlainTime::try_new(0, 0, 0, 0, 0, 0).unwrap(), } } } @@ -30,7 +30,7 @@ impl HeapMarkAndSweep for PlainTimeRecord<'static> { fn mark_values(&self, queues: &mut WorkQueues) { let Self { object_index, - plain_time: _, + _plain_time: _, } = self; object_index.mark_values(queues); @@ -38,7 +38,7 @@ impl HeapMarkAndSweep for PlainTimeRecord<'static> { fn sweep_values(&mut self, compactions: &CompactionLists) { let Self { object_index, - plain_time: _, + _plain_time: _, } = self; object_index.sweep_values(compactions); diff --git a/nova_vm/src/ecmascript/builtins/temporal/plain_time/plain_time_constructor.rs b/nova_vm/src/ecmascript/builtins/temporal/plain_time/plain_time_constructor.rs index 1f5d4654b..dfdaa712f 100644 --- a/nova_vm/src/ecmascript/builtins/temporal/plain_time/plain_time_constructor.rs +++ b/nova_vm/src/ecmascript/builtins/temporal/plain_time/plain_time_constructor.rs @@ -3,7 +3,12 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use crate::{ - ecmascript::{BUILTIN_STRING_MEMORY, Behaviour, Builtin, BuiltinIntrinsicConstructor, String}, + ecmascript::{ + Agent, ArgumentsList, BUILTIN_STRING_MEMORY, Behaviour, Builtin, + BuiltinIntrinsicConstructor, JsResult, Object, Realm, String, Value, + builders::BuiltinFunctionBuilder, + }, + engine::{GcScope, NoGcScope}, heap::IntrinsicConstructorIndexes, }; @@ -12,7 +17,7 @@ pub(crate) struct TemporalPlainTimeConstructor; impl Builtin for TemporalPlainTimeConstructor { const NAME: String<'static> = BUILTIN_STRING_MEMORY.PlainTime; - const LENGTH: u8 = 1; + const LENGTH: u8 = 0; const BEHAVIOUR: Behaviour = Behaviour::Constructor(TemporalPlainTimeConstructor::constructor); } impl BuiltinIntrinsicConstructor for TemporalPlainTimeConstructor { diff --git a/nova_vm/src/heap/heap_bits.rs b/nova_vm/src/heap/heap_bits.rs index e55efd350..901c9dcbd 100644 --- a/nova_vm/src/heap/heap_bits.rs +++ b/nova_vm/src/heap/heap_bits.rs @@ -1714,7 +1714,6 @@ pub(crate) struct CompactionLists { pub(crate) weak_refs: CompactionList, #[cfg(feature = "weak-refs")] pub(crate) weak_sets: CompactionList, - pub(crate) plain_times: (), } impl CompactionLists { From 8b8431e5aaedd8686203016565056c6830988ed2 Mon Sep 17 00:00:00 2001 From: Zeno Leonardi Date: Tue, 24 Feb 2026 15:36:37 +0100 Subject: [PATCH 3/5] feat(ecmascript): get PlainTime.prototype.minute --- nova_vm/src/builtin_strings | 2 + .../builtins/temporal/plain_time.rs | 25 ++++++++++-- .../builtins/temporal/plain_time/data.rs | 8 ++-- .../plain_time/plain_time_prototype.rs | 39 +++++++++++++++++-- 4 files changed, 62 insertions(+), 12 deletions(-) diff --git a/nova_vm/src/builtin_strings b/nova_vm/src/builtin_strings index 14fbf413c..5d57b4335 100644 --- a/nova_vm/src/builtin_strings +++ b/nova_vm/src/builtin_strings @@ -181,6 +181,7 @@ get description #[cfg(feature = "regexp")]get ignoreCase #[cfg(feature = "array-buffer")]get length #[cfg(feature = "array-buffer")]get maxByteLength +#[cfg(feature = "temporal")]get minute #[cfg(feature = "regexp")]get multiline #[cfg(feature = "array-buffer")]get resizable get size @@ -297,6 +298,7 @@ MAX_VALUE message #[cfg(feature = "temporal")]microseconds #[cfg(feature = "temporal")]milliseconds +#[cfg(feature = "temporal")]minute #[cfg(feature = "temporal")]minutes #[cfg(feature = "temporal")]months #[cfg(feature = "math")]min diff --git a/nova_vm/src/ecmascript/builtins/temporal/plain_time.rs b/nova_vm/src/ecmascript/builtins/temporal/plain_time.rs index be1ce4ae3..784ad266f 100644 --- a/nova_vm/src/ecmascript/builtins/temporal/plain_time.rs +++ b/nova_vm/src/ecmascript/builtins/temporal/plain_time.rs @@ -12,9 +12,10 @@ pub(crate) use plain_time_prototype::*; use crate::{ ecmascript::{ - Agent, InternalMethods, InternalSlots, OrdinaryObject, ProtoIntrinsics, object_handle, + Agent, ExceptionType, InternalMethods, InternalSlots, JsResult, OrdinaryObject, + ProtoIntrinsics, Value, object_handle, }, - engine::Bindable, + engine::{Bindable, NoGcScope}, heap::{ ArenaAccess, ArenaAccessMut, BaseIndex, CompactionLists, CreateHeapData, Heap, HeapMarkAndSweep, HeapSweepWeakReference, WorkQueues, arena_vec_access, @@ -33,8 +34,8 @@ arena_vec_access!( ); impl TemporalPlainTime<'_> { - pub(crate) fn _inner_plain_time(self, agent: &Agent) -> &temporal_rs::PlainTime { - &self.unbind().get(agent)._plain_time + pub(crate) fn inner_plain_time(self, agent: &Agent) -> &temporal_rs::PlainTime { + &self.unbind().get(agent).plain_time } } @@ -77,3 +78,19 @@ impl<'a> CreateHeapData, TemporalPlainTime<'a>> for Heap { TemporalPlainTime(BaseIndex::last(&self.plain_times)) } } + +#[inline(always)] +fn require_internal_slot_temporal_plain_time<'a>( + agent: &mut Agent, + value: Value, + gc: NoGcScope<'a, '_>, +) -> JsResult<'a, TemporalPlainTime<'a>> { + match value { + Value::PlainTime(plain_time) => Ok(plain_time.bind(gc)), + _ => Err(agent.throw_exception_with_static_message( + ExceptionType::TypeError, + "Object is not a Temporal PlainTime", + gc, + )), + } +} diff --git a/nova_vm/src/ecmascript/builtins/temporal/plain_time/data.rs b/nova_vm/src/ecmascript/builtins/temporal/plain_time/data.rs index 396fb9d0c..d7e3751e9 100644 --- a/nova_vm/src/ecmascript/builtins/temporal/plain_time/data.rs +++ b/nova_vm/src/ecmascript/builtins/temporal/plain_time/data.rs @@ -11,14 +11,14 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub struct PlainTimeRecord<'a> { pub(crate) object_index: Option>, - pub(crate) _plain_time: temporal_rs::PlainTime, + pub(crate) plain_time: temporal_rs::PlainTime, } impl PlainTimeRecord<'_> { pub fn default() -> Self { Self { object_index: None, - _plain_time: temporal_rs::PlainTime::try_new(0, 0, 0, 0, 0, 0).unwrap(), + plain_time: temporal_rs::PlainTime::try_new(0, 0, 0, 0, 0, 0).unwrap(), } } } @@ -30,7 +30,7 @@ impl HeapMarkAndSweep for PlainTimeRecord<'static> { fn mark_values(&self, queues: &mut WorkQueues) { let Self { object_index, - _plain_time: _, + plain_time: _, } = self; object_index.mark_values(queues); @@ -38,7 +38,7 @@ impl HeapMarkAndSweep for PlainTimeRecord<'static> { fn sweep_values(&mut self, compactions: &CompactionLists) { let Self { object_index, - _plain_time: _, + plain_time: _, } = self; object_index.sweep_values(compactions); diff --git a/nova_vm/src/ecmascript/builtins/temporal/plain_time/plain_time_prototype.rs b/nova_vm/src/ecmascript/builtins/temporal/plain_time/plain_time_prototype.rs index a8ef313cb..3fccbb185 100644 --- a/nova_vm/src/ecmascript/builtins/temporal/plain_time/plain_time_prototype.rs +++ b/nova_vm/src/ecmascript/builtins/temporal/plain_time/plain_time_prototype.rs @@ -3,23 +3,54 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use crate::{ - ecmascript::{Agent, BUILTIN_STRING_MEMORY, Realm, builders::OrdinaryObjectBuilder}, - engine::NoGcScope, + ecmascript::{ + Agent, ArgumentsList, BUILTIN_STRING_MEMORY, Behaviour, Builtin, BuiltinGetter, JsResult, + PropertyKey, Realm, String, Value, builders::OrdinaryObjectBuilder, + builtins::temporal::plain_time::require_internal_slot_temporal_plain_time, + }, + engine::{GcScope, NoGcScope}, heap::WellKnownSymbols, }; pub(crate) struct TemporalPlainTimePrototype; + +struct TemporalPlainTimePrototypeGetMinute; +impl Builtin for TemporalPlainTimePrototypeGetMinute { + const NAME: String<'static> = BUILTIN_STRING_MEMORY.get_minute; + const KEY: Option> = Some(BUILTIN_STRING_MEMORY.minute.to_property_key()); + const LENGTH: u8 = 0; + const BEHAVIOUR: Behaviour = Behaviour::Regular(TemporalPlainTimePrototype::get_minute); +} +impl BuiltinGetter for TemporalPlainTimePrototypeGetMinute {} + impl TemporalPlainTimePrototype { - pub fn create_intrinsic(agent: &mut Agent, realm: Realm<'static>, _: NoGcScope) { + /// ### [4.3.4 get Temporal.PlainTime.prototype.minute](https://tc39.es/proposal-temporal/#sec-get-temporal.plaintime.prototype.minute) + pub(crate) fn get_minute<'gc>( + agent: &mut Agent, + this_value: Value, + _: ArgumentsList, + gc: GcScope<'gc, '_>, + ) -> JsResult<'gc, Value<'gc>> { + let gc = gc.into_nogc(); + // 1. Let plainTime be the this value. + // 2. Perform ? RequireInternalSlot(plainTime, [[InitializedTemporalTime]]). + let plain_time = require_internal_slot_temporal_plain_time(agent, this_value, gc)?; + // 3. Return 𝔽(plainTime.[[Time]].[[Minute]]). + let value = plain_time.inner_plain_time(agent).minute(); + Ok(value.into()) + } + + pub(crate) fn create_intrinsic(agent: &mut Agent, realm: Realm<'static>, _: NoGcScope) { let intrinsics = agent.get_realm_record_by_id(realm).intrinsics(); let this = intrinsics.temporal_plain_time_prototype(); let object_prototype = intrinsics.object_prototype(); let plain_time_constructor = intrinsics.temporal_plain_time(); OrdinaryObjectBuilder::new_intrinsic_object(agent, realm, this) - .with_property_capacity(2) + .with_property_capacity(3) .with_prototype(object_prototype) .with_constructor_property(plain_time_constructor) + .with_builtin_function_getter_property::() .with_property(|builder| { builder .with_key(WellKnownSymbols::ToStringTag.into()) From b28b83b5469049c1076510e874084a5436728158 Mon Sep 17 00:00:00 2001 From: Zeno Leonardi Date: Tue, 24 Feb 2026 15:41:38 +0100 Subject: [PATCH 4/5] chore(test262): update expectations --- tests/expectations.json | 2 -- tests/metrics.json | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/expectations.json b/tests/expectations.json index c518a7e76..865339d93 100644 --- a/tests/expectations.json +++ b/tests/expectations.json @@ -3980,8 +3980,6 @@ "built-ins/Temporal/PlainTime/prototype/microsecond/prop-desc.js": "FAIL", "built-ins/Temporal/PlainTime/prototype/millisecond/branding.js": "FAIL", "built-ins/Temporal/PlainTime/prototype/millisecond/prop-desc.js": "FAIL", - "built-ins/Temporal/PlainTime/prototype/minute/branding.js": "FAIL", - "built-ins/Temporal/PlainTime/prototype/minute/prop-desc.js": "FAIL", "built-ins/Temporal/PlainTime/prototype/nanosecond/branding.js": "FAIL", "built-ins/Temporal/PlainTime/prototype/nanosecond/prop-desc.js": "FAIL", "built-ins/Temporal/PlainTime/prototype/round/branding.js": "FAIL", diff --git a/tests/metrics.json b/tests/metrics.json index e52e0bc4f..8fb7a2d4a 100644 --- a/tests/metrics.json +++ b/tests/metrics.json @@ -1,8 +1,8 @@ { "results": { "crash": 52, - "fail": 6971, - "pass": 40329, + "fail": 6969, + "pass": 40331, "skip": 3326, "timeout": 18, "unresolved": 37 From 28714b8fb37e6acd58a77be03b9d98c7e78ccb29 Mon Sep 17 00:00:00 2001 From: Zeno Leonardi Date: Mon, 2 Mar 2026 11:16:34 +0100 Subject: [PATCH 5/5] feat(temporal'): PlainTime constructor --- .../plain_time/plain_time_constructor.rs | 122 +++++++++++++++++- 1 file changed, 116 insertions(+), 6 deletions(-) diff --git a/nova_vm/src/ecmascript/builtins/temporal/plain_time/plain_time_constructor.rs b/nova_vm/src/ecmascript/builtins/temporal/plain_time/plain_time_constructor.rs index dfdaa712f..71c69df95 100644 --- a/nova_vm/src/ecmascript/builtins/temporal/plain_time/plain_time_constructor.rs +++ b/nova_vm/src/ecmascript/builtins/temporal/plain_time/plain_time_constructor.rs @@ -5,10 +5,11 @@ use crate::{ ecmascript::{ Agent, ArgumentsList, BUILTIN_STRING_MEMORY, Behaviour, Builtin, - BuiltinIntrinsicConstructor, JsResult, Object, Realm, String, Value, - builders::BuiltinFunctionBuilder, + BuiltinIntrinsicConstructor, ExceptionType, Function, JsResult, Object, Realm, String, + Value, builders::BuiltinFunctionBuilder, temporal_err_to_js_err, + to_integer_with_truncation, }, - engine::{GcScope, NoGcScope}, + engine::{Bindable as _, GcScope, NoGcScope, Scopable}, heap::IntrinsicConstructorIndexes, }; @@ -28,11 +29,120 @@ impl TemporalPlainTimeConstructor { fn constructor<'gc>( agent: &mut Agent, _: Value, - _args: ArgumentsList, - _new_target: Option, + args: ArgumentsList, + new_target: Option, gc: GcScope<'gc, '_>, ) -> JsResult<'gc, Value<'gc>> { - Err(agent.todo("Temporal.PlainTime", gc.into_nogc())) + let years = args.get(1).scope(agent, gc.nogc()); + let months = args.get(2).scope(agent, gc.nogc()); + let weeks = args.get(3).scope(agent, gc.nogc()); + let days = args.get(4).scope(agent, gc.nogc()); + let hours = args.get(5).scope(agent, gc.nogc()); + let minutes = args.get(6).scope(agent, gc.nogc()); + let seconds = args.get(7).scope(agent, gc.nogc()); + let milliseconds = args.get(8).scope(agent, gc.nogc()); + let microseconds = args.get(9).scope(agent, gc.nogc()); + let nanoseconds = args.get(10).scope(agent, gc.nogc()); + let new_target = new_target.bind(gc.nogc()); + + // 1. If NewTarget is undefined, throw a TypeError exception. + let Some(new_target) = new_target else { + return Err(agent.throw_exception_with_static_message( + ExceptionType::TypeError, + "calling a builtin Temporal.PlainTime constructor without new is forbidden", + gc.into_nogc(), + )); + }; + + let Ok(new_target) = Function::try_from(new_target) else { + unreachable!() + }; + let new_target = new_target.scope(agent, gc.nogc()); + + // 2. If hour is undefined, set hour to 0; else set hour to ? ToIntegerWithTruncation(hour). + let h = if hours.get(agent).is_undefined() { + Ok(0) + } else { + u8::try_from( + to_integer_with_truncation(agent, hours.get(agent), gc.reborrow()).unbind()?, + ) + }; + + // 3. If minute is undefined, set minute to 0; else set minute to ? ToIntegerWithTruncation(minute). + let m = if minutes.get(agent).is_undefined() { + Ok(0) + } else { + u8::try_from( + to_integer_with_truncation(agent, minutes.get(agent), gc.reborrow()).unbind()?, + ) + }; + + // 4. If second is undefined, set second to 0; else set second to ? ToIntegerWithTruncation(second). + let s = if seconds.get(agent).is_undefined() { + Ok(0) + } else { + u8::try_from( + to_integer_with_truncation(agent, seconds.get(agent), gc.reborrow()).unbind()?, + ) + }; + + // 5. If millisecond is undefined, set millisecond to 0; else set millisecond to ? ToIntegerWithTruncation(millisecond). + let ms = if milliseconds.get(agent).is_undefined() { + Ok(0) + } else { + u16::try_from( + to_integer_with_truncation(agent, milliseconds.get(agent), gc.reborrow()) + .unbind()?, + ) + }; + + // 6. If microsecond is undefined, set microsecond to 0; else set microsecond to ? ToIntegerWithTruncation(microsecond). + let mis = if microseconds.get(agent).is_undefined() { + Ok(0) + } else { + u16::try_from( + to_integer_with_truncation(agent, microseconds.get(agent), gc.reborrow()) + .unbind()?, + ) + }; + + // 7. If nanosecond is undefined, set nanosecond to 0; else set nanosecond to ? ToIntegerWithTruncation(nanosecond). + let ns = if nanoseconds.get(agent).is_undefined() { + Ok(0) + } else { + u16::try_from( + to_integer_with_truncation(agent, nanoseconds.get(agent), gc.reborrow()) + .unbind()?, + ) + }; + + // 8. If IsValidTime(hour, minute, second, millisecond, microsecond, nanosecond) is false, throw a RangeError exception. + + // 9. Let time be CreateTimeRecord(hour, minute, second, millisecond, microsecond, nanosecond). + let time = if let ( + Ok(hour), + Ok(minute), + Ok(second), + Ok(millisecond), + Ok(microsecond), + Ok(nanosecond), + ) = (h, m, s, ms, mis, ns) + { + temporal_rs::PlainTime::try_new( + hour, + minute, + second, + millisecond, + microsecond, + nanosecond, + ) + .map_err(|err| temporal_err_to_js_err(agent, err, gc)) + .unbind()? + } else { + todo!() // TODO: create range error + }; + + // 10. Return ? CreateTemporalTime(time, NewTarget). } pub(crate) fn create_intrinsic(agent: &mut Agent, realm: Realm<'static>, _gc: NoGcScope) {