[Temporal] Add monthDayFromFields to Calendar

Add AO: ISOMonthDayFromFields
Spec Text:
https://tc39.es/proposal-temporal/#sec-temporal.calendar.prototype.monthdayfromfields
https://tc39.es/proposal-temporal/#sec-temporal-isomonthdayfromfields

Bug: v8:11544
Change-Id: I8a04a8e61af8abdb902de33efbf5635b8e8300aa
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3408576
Commit-Queue: Frank Tang <ftang@chromium.org>
Reviewed-by: Adam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80360}
This commit is contained in:
Frank Tang 2022-05-04 15:21:58 -07:00 committed by V8 LUCI CQ
parent 10bbb38fed
commit bf54cc83a5
4 changed files with 156 additions and 41 deletions

View File

@ -294,8 +294,6 @@ TO_BE_IMPLEMENTED(TemporalTimeZonePrototypeToJSON)
/* Temporal.Calendar */
/* Temporal #sec-temporal.calendar.prototype.yearmonthfromfields */
TO_BE_IMPLEMENTED(TemporalCalendarPrototypeYearMonthFromFields)
/* Temporal #sec-temporal.calendar.prototype.monthdayfromfields */
TO_BE_IMPLEMENTED(TemporalCalendarPrototypeMonthDayFromFields)
/* Temporal #sec-temporal.calendar.prototype.dateadd */
TO_BE_IMPLEMENTED(TemporalCalendarPrototypeDateAdd)
/* Temporal #sec-temporal.calendar.prototype.weekofyear */
@ -795,6 +793,7 @@ TEMPORAL_PROTOTYPE_METHOD1(Calendar, InLeapYear, inLeapYear)
TEMPORAL_PROTOTYPE_METHOD2(Calendar, MergeFields, mergeFields)
TEMPORAL_PROTOTYPE_METHOD1(Calendar, Month, month)
TEMPORAL_PROTOTYPE_METHOD1(Calendar, MonthCode, monthCode)
TEMPORAL_PROTOTYPE_METHOD2(Calendar, MonthDayFromFields, monthDayFromFields)
TEMPORAL_PROTOTYPE_METHOD1(Calendar, MonthsInYear, monthsInYear)
TEMPORAL_PROTOTYPE_METHOD1(Calendar, Year, year)
TEMPORAL_TO_STRING(Calendar)

View File

@ -718,6 +718,15 @@ MaybeHandle<JSTemporalPlainMonthDay> CreateTemporalMonthDay(
return object;
}
MaybeHandle<JSTemporalPlainMonthDay> CreateTemporalMonthDay(
Isolate* isolate, int32_t iso_month, int32_t iso_day,
Handle<JSReceiver> calendar, int32_t reference_iso_year) {
TEMPORAL_ENTER_FUNC();
return CreateTemporalMonthDay(isolate, CONSTRUCTOR(plain_month_day),
CONSTRUCTOR(plain_month_day), iso_month,
iso_day, calendar, reference_iso_year);
}
// #sec-temporal-createtemporalyearmonth
MaybeHandle<JSTemporalPlainYearMonth> CreateTemporalYearMonth(
Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
@ -1766,7 +1775,6 @@ MaybeHandle<JSTemporalInstant> ToTemporalInstant(Isolate* isolate,
} // namespace
namespace temporal {
// #sec-temporal-totemporalcalendar
MaybeHandle<JSReceiver> ToTemporalCalendar(
Isolate* isolate, Handle<Object> temporal_calendar_like,
@ -5129,6 +5137,93 @@ double TotalDurationNanoseconds(Isolate* isolate,
return duration.nanoseconds + duration.microseconds * 1000;
}
Maybe<DateRecordCommon> RegulateISODate(Isolate* isolate, ShowOverflow overflow,
const DateRecordCommon& date);
Maybe<int32_t> ResolveISOMonth(Isolate* isolate, Handle<JSReceiver> fields);
// #sec-temporal-isomonthdayfromfields
Maybe<DateRecordCommon> ISOMonthDayFromFields(Isolate* isolate,
Handle<JSReceiver> fields,
Handle<JSReceiver> options,
const char* method_name) {
Factory* factory = isolate->factory();
// 1. Assert: Type(fields) is Object.
// 2. Let overflow be ? ToTemporalOverflow(options).
ShowOverflow overflow;
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, overflow, ToTemporalOverflow(isolate, options, method_name),
Nothing<DateRecordCommon>());
// 3. Set fields to ? PrepareTemporalFields(fields, « "day", "month",
// "monthCode", "year" », «»).
Handle<FixedArray> field_names = factory->NewFixedArray(4);
field_names->set(0, ReadOnlyRoots(isolate).day_string());
field_names->set(1, ReadOnlyRoots(isolate).month_string());
field_names->set(2, ReadOnlyRoots(isolate).monthCode_string());
field_names->set(3, ReadOnlyRoots(isolate).year_string());
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, fields,
PrepareTemporalFields(isolate, fields, field_names,
RequiredFields::kNone),
Nothing<DateRecordCommon>());
// 4. Let month be ! Get(fields, "month").
Handle<Object> month_obj =
Object::GetPropertyOrElement(isolate, fields, factory->month_string())
.ToHandleChecked();
// 5. Let monthCode be ! Get(fields, "monthCode").
Handle<Object> month_code_obj =
Object::GetPropertyOrElement(isolate, fields, factory->monthCode_string())
.ToHandleChecked();
// 6. Let year be ! Get(fields, "year").
Handle<Object> year_obj =
Object::GetPropertyOrElement(isolate, fields, factory->year_string())
.ToHandleChecked();
// 7. If month is not undefined, and monthCode and year are both undefined,
// then
if (!month_obj->IsUndefined(isolate) &&
month_code_obj->IsUndefined(isolate) && year_obj->IsUndefined(isolate)) {
// a. Throw a TypeError exception.
THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALID_ARG_TYPE_ERROR(),
Nothing<DateRecordCommon>());
}
// 8. Set month to ? ResolveISOMonth(fields).
DateRecordCommon result;
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, result.month,
ResolveISOMonth(isolate, fields),
Nothing<DateRecordCommon>());
// 9. Let day be ! Get(fields, "day").
Handle<Object> day_obj =
Object::GetPropertyOrElement(isolate, fields, factory->day_string())
.ToHandleChecked();
// 10. If day is undefined, throw a TypeError exception.
if (day_obj->IsUndefined(isolate)) {
THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALID_ARG_TYPE_ERROR(),
Nothing<DateRecordCommon>());
}
result.day = FastD2I(floor(day_obj->Number()));
// 11. Let referenceISOYear be 1972 (the first leap year after the Unix
// epoch).
int32_t reference_iso_year = 1972;
// 12. If monthCode is undefined, then
if (month_code_obj->IsUndefined(isolate)) {
result.year = FastD2I(floor(year_obj->Number()));
// a. Let result be ? RegulateISODate(year, month, day, overflow).
} else {
// 13. Else,
// a. Let result be ? RegulateISODate(referenceISOYear, month, day,
// overflow).
result.year = reference_iso_year;
}
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, result, RegulateISODate(isolate, overflow, result),
Nothing<DateRecordCommon>());
// 14. Return the new Record { [[Month]]: result.[[Month]], [[Day]]:
// result.[[Day]], [[ReferenceISOYear]]: referenceISOYear }.
result.year = reference_iso_year;
return Just(result);
}
} // namespace
// #sec-temporal.duration
@ -5455,19 +5550,14 @@ Maybe<DateRecordCommon> RegulateISODate(Isolate* isolate, ShowOverflow overflow,
// #sec-temporal-resolveisomonth
Maybe<int32_t> ResolveISOMonth(Isolate* isolate, Handle<JSReceiver> fields) {
Factory* factory = isolate->factory();
// 1. Let month be ? Get(fields, "month").
Handle<Object> month_obj;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, month_obj,
Object::GetPropertyOrElement(isolate, fields, factory->month_string()),
Nothing<int32_t>());
// 2. Let monthCode be ? Get(fields, "monthCode").
Handle<Object> month_code_obj;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, month_code_obj,
Object::GetPropertyOrElement(isolate, fields,
factory->monthCode_string()),
Nothing<int32_t>());
// 1. Let month be ! Get(fields, "month").
Handle<Object> month_obj =
Object::GetPropertyOrElement(isolate, fields, factory->month_string())
.ToHandleChecked();
// 2. Let monthCode be ! Get(fields, "monthCode").
Handle<Object> month_code_obj =
Object::GetPropertyOrElement(isolate, fields, factory->monthCode_string())
.ToHandleChecked();
// 3. If monthCode is undefined, then
if (month_code_obj->IsUndefined(isolate)) {
// a. If month is undefined, throw a TypeError exception.
@ -5558,12 +5648,10 @@ Maybe<DateRecordCommon> ISODateFromFields(Isolate* isolate,
RequiredFields::kNone),
Nothing<DateRecordCommon>());
// 4. Let year be ? Get(fields, "year").
Handle<Object> year_obj;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, year_obj,
Object::GetPropertyOrElement(isolate, fields, factory->year_string()),
Nothing<DateRecordCommon>());
// 4. Let year be ! Get(fields, "year").
Handle<Object> year_obj =
Object::GetPropertyOrElement(isolate, fields, factory->year_string())
.ToHandleChecked();
// 5. If year is undefined, throw a TypeError exception.
if (year_obj->IsUndefined(isolate)) {
THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALID_ARG_TYPE_ERROR(),
@ -5578,12 +5666,10 @@ Maybe<DateRecordCommon> ISODateFromFields(Isolate* isolate,
Maybe<int32_t> maybe_month = ResolveISOMonth(isolate, fields);
MAYBE_RETURN(maybe_month, Nothing<DateRecordCommon>());
// 7. Let day be ? Get(fields, "day").
Handle<Object> day_obj;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, day_obj,
Object::GetPropertyOrElement(isolate, fields, factory->day_string()),
Nothing<DateRecordCommon>());
// 7. Let day be ! Get(fields, "day").
Handle<Object> day_obj =
Object::GetPropertyOrElement(isolate, fields, factory->day_string())
.ToHandleChecked();
// 8. If day is undefined, throw a TypeError exception.
if (day_obj->IsUndefined(isolate)) {
THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALID_ARG_TYPE_ERROR(),
@ -6322,6 +6408,44 @@ MaybeHandle<Smi> JSTemporalCalendar::Month(Isolate* isolate,
return handle(Smi::FromInt(month), isolate);
}
// #sec-temporal.calendar.prototype.monthdayfromfields
MaybeHandle<JSTemporalPlainMonthDay> JSTemporalCalendar::MonthDayFromFields(
Isolate* isolate, Handle<JSTemporalCalendar> calendar,
Handle<Object> fields_obj, Handle<Object> options_obj) {
// 1. Let calendar be the this value.
// 2. Perform ? RequireInternalSlot(calendar,
// [[InitializedTemporalCalendar]]).
// 3. Assert: calendar.[[Identifier]] is "iso8601".
const char* method_name = "Temporal.Calendar.prototype.monthDayFromFields";
// 4. If Type(fields) is not Object, throw a TypeError exception.
if (!fields_obj->IsJSReceiver()) {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kCalledOnNonObject,
isolate->factory()->NewStringFromAsciiChecked(
method_name)),
JSTemporalPlainMonthDay);
}
Handle<JSReceiver> fields = Handle<JSReceiver>::cast(fields_obj);
// 5. Set options to ? GetOptionsObject(options).
Handle<JSReceiver> options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options, GetOptionsObject(isolate, options_obj, method_name),
JSTemporalPlainMonthDay);
// 6. Let result be ? ISOMonthDayFromFields(fields, options).
if (calendar->calendar_index() == 0) {
Maybe<DateRecordCommon> maybe_result =
ISOMonthDayFromFields(isolate, fields, options, method_name);
MAYBE_RETURN(maybe_result, Handle<JSTemporalPlainMonthDay>());
DateRecordCommon result = maybe_result.FromJust();
// 7. Return ? CreateTemporalMonthDay(result.[[Month]], result.[[Day]],
// calendar, result.[[ReferenceISOYear]]).
return CreateTemporalMonthDay(isolate, result.month, result.day, calendar,
result.year);
}
// TODO(ftang) add intl code inside #ifdef V8_INTL_SUPPORT
UNREACHABLE();
}
// #sec-temporal.calendar.prototype.tostring
MaybeHandle<String> JSTemporalCalendar::ToString(
Isolate* isolate, Handle<JSTemporalCalendar> calendar,

View File

@ -102,6 +102,11 @@ class JSTemporalCalendar
Isolate* isolate, Handle<JSTemporalCalendar> calendar,
Handle<Object> fields, Handle<Object> options);
// #sec-temporal.calendar.prototype.monthdayfromfields
V8_WARN_UNUSED_RESULT static MaybeHandle<JSTemporalPlainMonthDay>
MonthDayFromFields(Isolate* isolate, Handle<JSTemporalCalendar> calendar,
Handle<Object> fields, Handle<Object> options);
// #sec-temporal.calendar.prototype.mergefields
V8_WARN_UNUSED_RESULT static MaybeHandle<JSReceiver> MergeFields(
Isolate* isolate, Handle<JSTemporalCalendar> calendar,

View File

@ -400,12 +400,6 @@
'built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-datefromfields-called-with-options-undefined': [FAIL],
'built-ins/Temporal/Calendar/prototype/month/calendar-datefromfields-called-with-options-undefined': [FAIL],
'built-ins/Temporal/Calendar/prototype/monthCode/calendar-datefromfields-called-with-options-undefined': [FAIL],
'built-ins/Temporal/Calendar/prototype/monthDayFromFields/basic': [FAIL],
'built-ins/Temporal/Calendar/prototype/monthDayFromFields/fields-missing-properties': [FAIL],
'built-ins/Temporal/Calendar/prototype/monthDayFromFields/monthcode-invalid': [FAIL],
'built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-constrain': [FAIL],
'built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-reject': [FAIL],
'built-ins/Temporal/Calendar/prototype/monthDayFromFields/reference-year-1972': [FAIL],
'built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-datefromfields-called-with-options-undefined': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindate': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindatetime': [FAIL],
@ -471,12 +465,6 @@
'built-ins/Temporal/Calendar/prototype/daysInYear/basic': [FAIL],
'built-ins/Temporal/Calendar/prototype/month/basic': [FAIL],
'built-ins/Temporal/Calendar/prototype/monthCode/basic': [FAIL],
'built-ins/Temporal/Calendar/prototype/monthDayFromFields/branding': [FAIL],
'built-ins/Temporal/Calendar/prototype/monthDayFromFields/fields-not-object': [FAIL],
'built-ins/Temporal/Calendar/prototype/monthDayFromFields/infinity-throws-rangeerror': [FAIL],
'built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-invalid-string': [FAIL],
'built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-undefined': [FAIL],
'built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-wrong-type': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-with-utc-designator': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable': [FAIL],
@ -2579,7 +2567,6 @@
'intl402/Temporal/Calendar/prototype/eraYear/argument-string-invalid': [FAIL],
'built-ins/Temporal/Calendar/prototype/dateAdd/options-wrong-type': [FAIL],
'built-ins/Temporal/Calendar/prototype/monthDayFromFields/options-wrong-type': [FAIL],
'built-ins/Temporal/Calendar/prototype/yearMonthFromFields/options-wrong-type': [FAIL],
'built-ins/Temporal/Duration/compare/options-wrong-type': [FAIL],
'built-ins/Temporal/Duration/prototype/add/options-wrong-type': [FAIL],