Diff
Modified: trunk/JSTests/ChangeLog (293996 => 293997)
--- trunk/JSTests/ChangeLog 2022-05-10 02:52:56 UTC (rev 293996)
+++ trunk/JSTests/ChangeLog 2022-05-10 03:49:35 UTC (rev 293997)
@@ -1,5 +1,21 @@
2022-05-09 Ross Kirsling <ross.kirsl...@sony.com>
+ Temporal round and total methods should accept string param
+ https://bugs.webkit.org/show_bug.cgi?id=240249
+
+ Reviewed by Yusuke Suzuki.
+
+ * stress/temporal-duration.js:
+ * stress/temporal-instant.js:
+ * stress/temporal-plaintime.js:
+ Add test cases.
+
+ * test262/expectations.yaml:
+ Mark 24 test cases passing.
+ (This number should be 26, but two still fail as the harness expects PlainDateTime and ZonedDateTime to exist.)
+
+2022-05-09 Ross Kirsling <ross.kirsl...@sony.com>
+
Temporal and Date must reject expanded year -000000
https://bugs.webkit.org/show_bug.cgi?id=240263
Modified: trunk/JSTests/stress/temporal-duration.js (293996 => 293997)
--- trunk/JSTests/stress/temporal-duration.js 2022-05-10 02:52:56 UTC (rev 293996)
+++ trunk/JSTests/stress/temporal-duration.js 2022-05-10 03:49:35 UTC (rev 293997)
@@ -203,6 +203,7 @@
shouldThrow(() => Temporal.Duration.from('P1W').round({ largestUnit: 'seconds' }), RangeError);
shouldThrow(() => Temporal.Duration.from('P1D').round({ largestUnit: 'months' }), RangeError);
shouldThrow(() => Temporal.Duration.from('P1D').round({ largestUnit: 'weeks' }), RangeError);
+shouldBe(posAbsolute.round('day').toString(), 'P1D');
shouldBe(posAbsolute.round({ largestUnit: 'day' }).toString(), 'P1DT2H3M4.005006007S');
shouldBe(posAbsolute.round({ largestUnit: 'auto' }).toString(), 'P1DT2H3M4.005006007S');
shouldBe(posAbsolute.round({ smallestUnit: 'day' }).toString(), 'P1D');
@@ -229,6 +230,7 @@
shouldThrow(() => Temporal.Duration.from('P1W').total({ unit: 'seconds' }), RangeError);
shouldThrow(() => Temporal.Duration.from('P1D').total({ unit: 'months' }), RangeError);
shouldThrow(() => Temporal.Duration.from('P1D').total({ unit: 'weeks' }), RangeError);
+shouldBe(posAbsolute.total('days'), 1.0854630209028588);
shouldBe(posAbsolute.total({ unit: 'days' }), 1.0854630209028588);
shouldBe(posAbsolute.total({ unit: 'hours' }), 26.051112501668612);
shouldBe(posAbsolute.total({ unit: 'minutes' }), 1563.0667501001167);
Modified: trunk/JSTests/stress/temporal-instant.js (293996 => 293997)
--- trunk/JSTests/stress/temporal-instant.js 2022-05-10 02:52:56 UTC (rev 293996)
+++ trunk/JSTests/stress/temporal-instant.js 2022-05-10 03:49:35 UTC (rev 293997)
@@ -229,6 +229,10 @@
// truncates to minute
[i1, i2, i3].forEach((i) => shouldBe(i.toString({ smallestUnit: 'minute' }), '1976-11-18T15:23Z'));
+ // ...as opposed to rounding first
+ shouldBe(i3.round('minute').toString(), '1976-11-18T15:24:00Z');
+ shouldBe(i3.round({ smallestUnit: 'minute' }).toString(), '1976-11-18T15:24:00Z');
+
// other smallestUnits are aliases for fractional digits
shouldBe(i3.toString({ smallestUnit: 'second' }), i3.toString({ fractionalSecondDigits: 0 }));
shouldBe(i3.toString({ smallestUnit: 'millisecond' }), i3.toString({ fractionalSecondDigits: 3 }));
Modified: trunk/JSTests/stress/temporal-plaintime.js (293996 => 293997)
--- trunk/JSTests/stress/temporal-plaintime.js 2022-05-10 02:52:56 UTC (rev 293996)
+++ trunk/JSTests/stress/temporal-plaintime.js 2022-05-10 03:49:35 UTC (rev 293997)
@@ -284,6 +284,7 @@
{
let time = Temporal.PlainTime.from('19:39:09.068346205');
+ shouldBe(String(time.round('hour')), `20:00:00`);
shouldBe(String(time.round({ smallestUnit: 'hour' })), `20:00:00`);
shouldBe(String(time.round({ roundingIncrement: 30, smallestUnit: 'minute' })), `19:30:00`);
shouldBe(String(time.round({ roundingIncrement: 30, smallestUnit: 'minute', roundingMode: 'ceil' })), `20:00:00`);
Modified: trunk/JSTests/test262/expectations.yaml (293996 => 293997)
--- trunk/JSTests/test262/expectations.yaml 2022-05-10 02:52:56 UTC (rev 293996)
+++ trunk/JSTests/test262/expectations.yaml 2022-05-10 03:49:35 UTC (rev 293997)
@@ -948,18 +948,6 @@
test/built-ins/Temporal/Duration/prototype/round/relativeto-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js:
default: "TypeError: undefined is not a constructor (evaluating 'new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone)')"
strict mode: "TypeError: undefined is not a constructor (evaluating 'new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone)')"
-test/built-ins/Temporal/Duration/prototype/round/roundto-invalid-string.js:
- default: 'Test262Error: "era" is not a valid value for smallest unit Expected a RangeError but got a TypeError'
- strict mode: 'Test262Error: "era" is not a valid value for smallest unit Expected a RangeError but got a TypeError'
-test/built-ins/Temporal/Duration/prototype/round/smallestunit-plurals-accepted-string.js:
- default: 'TypeError: options argument is not an object or undefined'
- strict mode: 'TypeError: options argument is not an object or undefined'
-test/built-ins/Temporal/Duration/prototype/round/smallestunit-string-shorthand-string.js:
- default: 'TypeError: options argument is not an object or undefined'
- strict mode: 'TypeError: options argument is not an object or undefined'
-test/built-ins/Temporal/Duration/prototype/round/smallestunit.js:
- default: 'TypeError: options argument is not an object or undefined'
- strict mode: 'TypeError: options argument is not an object or undefined'
test/built-ins/Temporal/Duration/prototype/round/timezone-string-leap-second.js:
default: 'RangeError: Cannot round a duration of years, months, or weeks without a relativeTo option'
strict mode: 'RangeError: Cannot round a duration of years, months, or weeks without a relativeTo option'
@@ -1038,9 +1026,6 @@
test/built-ins/Temporal/Duration/prototype/total/relativeto-propertybag-timezone-getoffsetnanosecondsfor-not-callable.js:
default: 'Test262Error: Uncallable undefined getOffsetNanosecondsFor should throw TypeError Expected a TypeError but got a RangeError'
strict mode: 'Test262Error: Uncallable undefined getOffsetNanosecondsFor should throw TypeError Expected a TypeError but got a RangeError'
-test/built-ins/Temporal/Duration/prototype/total/relativeto-undefined-throw-on-calendar-units.js:
- default: 'TypeError: options argument is not an object or undefined'
- strict mode: 'TypeError: options argument is not an object or undefined'
test/built-ins/Temporal/Duration/prototype/total/relativeto-wrong-type.js:
default: "TypeError: undefined is not an object (evaluating 'Temporal.ZonedDateTime.prototype')"
strict mode: "TypeError: undefined is not an object (evaluating 'Temporal.ZonedDateTime.prototype')"
@@ -1053,27 +1038,12 @@
test/built-ins/Temporal/Duration/prototype/total/timezone-wrong-type.js:
default: 'Test262Error: symbol is not a valid object and does not convert to a string Expected a TypeError but got a RangeError'
strict mode: 'Test262Error: symbol is not a valid object and does not convert to a string Expected a TypeError but got a RangeError'
-test/built-ins/Temporal/Duration/prototype/total/unit-disallowed-units-string.js:
- default: 'Test262Error: "era" should not be allowed as an argument to total Expected a RangeError but got a TypeError'
- strict mode: 'Test262Error: "era" should not be allowed as an argument to total Expected a RangeError but got a TypeError'
test/built-ins/Temporal/Duration/prototype/total/unit-plurals-accepted-string.js:
- default: 'TypeError: options argument is not an object or undefined'
- strict mode: 'TypeError: options argument is not an object or undefined'
-test/built-ins/Temporal/Duration/prototype/total/unit-string-shorthand-string.js:
- default: 'TypeError: options argument is not an object or undefined'
- strict mode: 'TypeError: options argument is not an object or undefined'
+ default: 'TypeError: Right hand side of instanceof is not an object'
+ strict mode: 'TypeError: Right hand side of instanceof is not an object'
test/built-ins/Temporal/Instant/prototype/round/rounding-direction.js:
default: 'Test262Error: Rounding down is towards the Big Bang, not the epoch or 1 BCE (roundingMode trunc) Expected SameValue(«-65261246399000000000», «-65261246400000000000») to be true'
strict mode: 'Test262Error: Rounding down is towards the Big Bang, not the epoch or 1 BCE (roundingMode trunc) Expected SameValue(«-65261246399000000000», «-65261246400000000000») to be true'
-test/built-ins/Temporal/Instant/prototype/round/roundto-invalid-string.js:
- default: 'Test262Error: "era" is not a valid value for smallest unit Expected a RangeError but got a TypeError'
- strict mode: 'Test262Error: "era" is not a valid value for smallest unit Expected a RangeError but got a TypeError'
-test/built-ins/Temporal/Instant/prototype/round/smallestunit-plurals-accepted.js:
- default: 'TypeError: options argument is not an object or undefined'
- strict mode: 'TypeError: options argument is not an object or undefined'
-test/built-ins/Temporal/Instant/prototype/round/smallestunit-string-shorthand.js:
- default: 'TypeError: options argument is not an object or undefined'
- strict mode: 'TypeError: options argument is not an object or undefined'
test/built-ins/Temporal/Instant/prototype/since/largestunit.js:
default: 'Test262Error: does not include higher units than necessary (largest unit unspecified) nanoseconds result Expected SameValue(«40», «101») to be true'
strict mode: 'Test262Error: does not include higher units than necessary (largest unit unspecified) nanoseconds result Expected SameValue(«40», «101») to be true'
@@ -1170,12 +1140,6 @@
test/built-ins/Temporal/PlainTime/prototype/equals/plaintime-propertybag-no-time-units.js:
default: 'TypeError: "hour" field is missing'
strict mode: 'TypeError: "hour" field is missing'
-test/built-ins/Temporal/PlainTime/prototype/round/roundto-invalid-string.js:
- default: 'Test262Error: "era" is not a valid value for smallest unit Expected a RangeError but got a TypeError'
- strict mode: 'Test262Error: "era" is not a valid value for smallest unit Expected a RangeError but got a TypeError'
-test/built-ins/Temporal/PlainTime/prototype/round/smallestunit-string-shorthand.js:
- default: 'TypeError: options argument is not an object or undefined'
- strict mode: 'TypeError: options argument is not an object or undefined'
test/built-ins/Temporal/PlainTime/prototype/since/argument-cast.js:
default: 'TypeError: "microsecond" field is missing'
strict mode: 'TypeError: "microsecond" field is missing'
Modified: trunk/Source/_javascript_Core/ChangeLog (293996 => 293997)
--- trunk/Source/_javascript_Core/ChangeLog 2022-05-10 02:52:56 UTC (rev 293996)
+++ trunk/Source/_javascript_Core/ChangeLog 2022-05-10 03:49:35 UTC (rev 293997)
@@ -1,5 +1,26 @@
2022-05-09 Ross Kirsling <ross.kirsl...@sony.com>
+ Temporal round and total methods should accept string param
+ https://bugs.webkit.org/show_bug.cgi?id=240249
+
+ Reviewed by Yusuke Suzuki.
+
+ This patch implements https://github.com/tc39/proposal-temporal/pull/1875,
+ which allows certain required string options to be passed directly instead of as part of an options object.
+
+ Namely:
+ - `{Duration, Instant, PlainTime}::round` now accept `smallestUnit` as a string param
+ - `Duration::total` now accepts `unit` as a string param
+
+ * runtime/TemporalDuration.cpp:
+ (JSC::TemporalDuration::round const):
+ (JSC::TemporalDuration::total const):
+ * runtime/TemporalInstant.cpp:
+ * runtime/TemporalPlainTime.cpp:
+ (JSC::TemporalPlainTime::round const):
+
+2022-05-09 Ross Kirsling <ross.kirsl...@sony.com>
+
Temporal and Date must reject expanded year -000000
https://bugs.webkit.org/show_bug.cgi?id=240263
Modified: trunk/Source/_javascript_Core/runtime/TemporalDuration.cpp (293996 => 293997)
--- trunk/Source/_javascript_Core/runtime/TemporalDuration.cpp 2022-05-10 02:52:56 UTC (rev 293996)
+++ trunk/Source/_javascript_Core/runtime/TemporalDuration.cpp 2022-05-10 03:49:35 UTC (rev 293997)
@@ -462,26 +462,39 @@
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
- JSObject* options = intlGetOptionsObject(globalObject, optionsValue);
- RETURN_IF_EXCEPTION(scope, { });
+ JSObject* options = nullptr;
+ std::optional<TemporalUnit> smallest;
+ std::optional<TemporalUnit> largest;
+ TemporalUnit defaultLargestUnit = largestSubduration(m_duration);
+ if (optionsValue.isString()) {
+ auto string = optionsValue.toWTFString(globalObject);
+ RETURN_IF_EXCEPTION(scope, { });
- auto smallest = temporalSmallestUnit(globalObject, options, { });
- RETURN_IF_EXCEPTION(scope, { });
+ smallest = temporalUnitType(string);
+ if (!smallest) {
+ throwRangeError(globalObject, scope, "smallestUnit is an invalid Temporal unit"_s);
+ return { };
+ }
+ } else {
+ options = intlGetOptionsObject(globalObject, optionsValue);
+ RETURN_IF_EXCEPTION(scope, { });
- TemporalUnit defaultLargestUnit = largestSubduration(m_duration);
- auto largest = temporalLargestUnit(globalObject, options, { }, defaultLargestUnit);
- RETURN_IF_EXCEPTION(scope, { });
+ smallest = temporalSmallestUnit(globalObject, options, { });
+ RETURN_IF_EXCEPTION(scope, { });
- if (!smallest && !largest) {
- throwRangeError(globalObject, scope, "Cannot round without a smallestUnit or largestUnit option"_s);
- return { };
- }
+ largest = temporalLargestUnit(globalObject, options, { }, defaultLargestUnit);
+ RETURN_IF_EXCEPTION(scope, { });
- if (smallest && largest && smallest.value() < largest.value()) {
- throwRangeError(globalObject, scope, "smallestUnit must be smaller than largestUnit"_s);
- return { };
+ if (!smallest && !largest) {
+ throwRangeError(globalObject, scope, "Cannot round without a smallestUnit or largestUnit option"_s);
+ return { };
+ }
+
+ if (smallest && largest && smallest.value() < largest.value()) {
+ throwRangeError(globalObject, scope, "smallestUnit must be smaller than largestUnit"_s);
+ return { };
+ }
}
-
TemporalUnit smallestUnit = smallest.value_or(TemporalUnit::Nanosecond);
TemporalUnit largestUnit = largest.value_or(std::min(defaultLargestUnit, smallestUnit));
@@ -512,11 +525,17 @@
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
- JSObject* options = intlGetOptionsObject(globalObject, optionsValue);
- RETURN_IF_EXCEPTION(scope, 0);
+ String unitString;
+ if (optionsValue.isString()) {
+ unitString = optionsValue.toWTFString(globalObject);
+ RETURN_IF_EXCEPTION(scope, 0);
+ } else {
+ JSObject* options = intlGetOptionsObject(globalObject, optionsValue);
+ RETURN_IF_EXCEPTION(scope, 0);
- String unitString = intlStringOption(globalObject, options, vm.propertyNames->unit, { }, { }, { });
- RETURN_IF_EXCEPTION(scope, 0);
+ unitString = intlStringOption(globalObject, options, vm.propertyNames->unit, { }, { }, { });
+ RETURN_IF_EXCEPTION(scope, 0);
+ }
auto unitType = temporalUnitType(unitString);
if (!unitType) {
Modified: trunk/Source/_javascript_Core/runtime/TemporalInstant.cpp (293996 => 293997)
--- trunk/Source/_javascript_Core/runtime/TemporalInstant.cpp 2022-05-10 02:52:56 UTC (rev 293996)
+++ trunk/Source/_javascript_Core/runtime/TemporalInstant.cpp 2022-05-10 03:49:35 UTC (rev 293997)
@@ -362,17 +362,35 @@
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
- JSObject* options = intlGetOptionsObject(globalObject, optionsValue);
- RETURN_IF_EXCEPTION(scope, { });
+ JSObject* options = nullptr;
+ std::optional<TemporalUnit> smallest;
+ if (optionsValue.isString()) {
+ auto string = optionsValue.toWTFString(globalObject);
+ RETURN_IF_EXCEPTION(scope, { });
- auto smallest = temporalSmallestUnit(globalObject, options, { TemporalUnit::Year, TemporalUnit::Month, TemporalUnit::Week, TemporalUnit::Day });
- RETURN_IF_EXCEPTION(scope, { });
+ smallest = temporalUnitType(string);
+ if (!smallest) {
+ throwRangeError(globalObject, scope, "smallestUnit is an invalid Temporal unit"_s);
+ return { };
+ }
- if (!smallest) {
- throwRangeError(globalObject, scope, "Cannot round without a smallestUnit option"_s);
- return { };
+ if (smallest.value() <= TemporalUnit::Day) {
+ throwRangeError(globalObject, scope, "smallestUnit is a disallowed unit"_s);
+ return { };
+ }
+ } else {
+ options = intlGetOptionsObject(globalObject, optionsValue);
+ RETURN_IF_EXCEPTION(scope, { });
+
+ smallest = temporalSmallestUnit(globalObject, options, { TemporalUnit::Year, TemporalUnit::Month, TemporalUnit::Week, TemporalUnit::Day });
+ RETURN_IF_EXCEPTION(scope, { });
+
+ if (!smallest) {
+ throwRangeError(globalObject, scope, "Cannot round without a smallestUnit option"_s);
+ return { };
+ }
}
- TemporalUnit smallestUnit = smallest.value_or(TemporalUnit::Nanosecond);
+ TemporalUnit smallestUnit = smallest.value();
RoundingMode roundingMode = temporalRoundingMode(globalObject, options, RoundingMode::HalfExpand);
RETURN_IF_EXCEPTION(scope, { });
Modified: trunk/Source/_javascript_Core/runtime/TemporalPlainTime.cpp (293996 => 293997)
--- trunk/Source/_javascript_Core/runtime/TemporalPlainTime.cpp 2022-05-10 02:52:56 UTC (rev 293996)
+++ trunk/Source/_javascript_Core/runtime/TemporalPlainTime.cpp 2022-05-10 03:49:35 UTC (rev 293997)
@@ -228,14 +228,32 @@
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
- JSObject* options = intlGetOptionsObject(globalObject, optionsValue);
- RETURN_IF_EXCEPTION(scope, { });
+ JSObject* options = nullptr;
+ std::optional<TemporalUnit> smallest;
+ if (optionsValue.isString()) {
+ auto string = optionsValue.toWTFString(globalObject);
+ RETURN_IF_EXCEPTION(scope, { });
- auto smallest = temporalSmallestUnit(globalObject, options, { TemporalUnit::Year, TemporalUnit::Month, TemporalUnit::Week, TemporalUnit::Day });
- RETURN_IF_EXCEPTION(scope, { });
- if (!smallest) {
- throwRangeError(globalObject, scope, "Cannot round without a smallestUnit option"_s);
- return { };
+ smallest = temporalUnitType(string);
+ if (!smallest) {
+ throwRangeError(globalObject, scope, "smallestUnit is an invalid Temporal unit"_s);
+ return { };
+ }
+
+ if (smallest.value() <= TemporalUnit::Day) {
+ throwRangeError(globalObject, scope, "smallestUnit is a disallowed unit"_s);
+ return { };
+ }
+ } else {
+ options = intlGetOptionsObject(globalObject, optionsValue);
+ RETURN_IF_EXCEPTION(scope, { });
+
+ smallest = temporalSmallestUnit(globalObject, options, { TemporalUnit::Year, TemporalUnit::Month, TemporalUnit::Week, TemporalUnit::Day });
+ RETURN_IF_EXCEPTION(scope, { });
+ if (!smallest) {
+ throwRangeError(globalObject, scope, "Cannot round without a smallestUnit option"_s);
+ return { };
+ }
}
TemporalUnit smallestUnit = smallest.value();