Skip to content

Commit

Permalink
Normative: Validate receiver fields before fields of any param objects
Browse files Browse the repository at this point in the history
Changes to the order of observable operations in
- PlainDate.p.with
- PlainDateTime.p.with
- PlainMonthDay.p.with
- PlainTime.p.with
- PlainYearMonth.p.since
- PlainYearMonth.p.until
- PlainYearMonth.p.with
- ZonedDateTime.p.with

Swapping the PrepareTemporalFields calls in ZonedDateTime.p.with exposed
another unnecessary user call: the 'timeZone' field was observably read
from the receiver and from the object returned from mergeFields(), but
never used. This is fixed as well.

Closes: #2462
  • Loading branch information
ptomato committed Jan 18, 2023
1 parent 67c8d23 commit f35fc58
Show file tree
Hide file tree
Showing 13 changed files with 28 additions and 30 deletions.
6 changes: 3 additions & 3 deletions polyfill/lib/ecmascript.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3797,12 +3797,12 @@ export const ES = ObjectAssign({}, ES2022, {
const settings = ES.GetDifferenceSettings(operation, options, 'date', ['week', 'day'], 'month', 'year');

const fieldNames = ES.CalendarFields(calendar, ['monthCode', 'year']);
const otherFields = ES.PrepareTemporalFields(other, fieldNames, []);
otherFields.day = 1;
const otherDate = ES.CalendarDateFromFields(calendar, otherFields);
const thisFields = ES.PrepareTemporalFields(yearMonth, fieldNames, []);
thisFields.day = 1;
const thisDate = ES.CalendarDateFromFields(calendar, thisFields);
const otherFields = ES.PrepareTemporalFields(other, fieldNames, []);
otherFields.day = 1;
const otherDate = ES.CalendarDateFromFields(calendar, otherFields);

const untilOptions = ObjectCreate(null);
ES.CopyDataProperties(untilOptions, options, []);
Expand Down
5 changes: 2 additions & 3 deletions polyfill/lib/plaindate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,15 @@ export class PlainDate {
throw new TypeError('invalid argument');
}
ES.RejectObjectWithCalendarOrTimeZone(temporalDateLike);
options = ES.GetOptionsObject(options);

const calendar = GetSlot(this, CALENDAR);
const fieldNames = ES.CalendarFields(calendar, ['day', 'month', 'monthCode', 'year']);
const partialDate = ES.PrepareTemporalFields(temporalDateLike, fieldNames, 'partial');
let fields = ES.PrepareTemporalFields(this, fieldNames, []);
const partialDate = ES.PrepareTemporalFields(temporalDateLike, fieldNames, 'partial');
fields = ES.CalendarMergeFields(calendar, fields, partialDate);
fields = ES.PrepareTemporalFields(fields, fieldNames, []);

options = ES.GetOptionsObject(options);

return ES.CalendarDateFromFields(calendar, fields, options);
}
withCalendar(calendar) {
Expand Down
2 changes: 1 addition & 1 deletion polyfill/lib/plaindatetime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,8 @@ export class PlainDateTime {
'second',
'year'
]);
const partialDateTime = ES.PrepareTemporalFields(temporalDateTimeLike, fieldNames, 'partial');
let fields = ES.PrepareTemporalFields(this, fieldNames, []);
const partialDateTime = ES.PrepareTemporalFields(temporalDateTimeLike, fieldNames, 'partial');
fields = ES.CalendarMergeFields(calendar, fields, partialDateTime);
fields = ES.PrepareTemporalFields(fields, fieldNames, []);
const { year, month, day, hour, minute, second, millisecond, microsecond, nanosecond } =
Expand Down
4 changes: 2 additions & 2 deletions polyfill/lib/plainmonthday.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ export class PlainMonthDay {
throw new TypeError('invalid argument');
}
ES.RejectObjectWithCalendarOrTimeZone(temporalMonthDayLike);
options = ES.GetOptionsObject(options);

const calendar = GetSlot(this, CALENDAR);
const fieldNames = ES.CalendarFields(calendar, ['day', 'month', 'monthCode', 'year']);
const partialMonthDay = ES.PrepareTemporalFields(temporalMonthDayLike, fieldNames, 'partial');
let fields = ES.PrepareTemporalFields(this, fieldNames, []);
const partialMonthDay = ES.PrepareTemporalFields(temporalMonthDayLike, fieldNames, 'partial');
fields = ES.CalendarMergeFields(calendar, fields, partialMonthDay);
fields = ES.PrepareTemporalFields(fields, fieldNames, []);

options = ES.GetOptionsObject(options);
return ES.CalendarMonthDayFromFields(calendar, fields, options);
}
equals(other) {
Expand Down
4 changes: 2 additions & 2 deletions polyfill/lib/plaintime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,11 @@ export class PlainTime {
throw new TypeError('invalid argument');
}
ES.RejectObjectWithCalendarOrTimeZone(temporalTimeLike);

const partialTime = ES.ToTemporalTimeRecord(temporalTimeLike, 'partial');
options = ES.GetOptionsObject(options);
const overflow = ES.ToTemporalOverflow(options);

const partialTime = ES.ToTemporalTimeRecord(temporalTimeLike, 'partial');

const fields = ES.ToTemporalTimeRecord(this);
let { hour, minute, second, millisecond, microsecond, nanosecond } = ObjectAssign(fields, partialTime);
({ hour, minute, second, millisecond, microsecond, nanosecond } = ES.RegulateTime(
Expand Down
5 changes: 2 additions & 3 deletions polyfill/lib/plainyearmonth.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,15 @@ export class PlainYearMonth {
throw new TypeError('invalid argument');
}
ES.RejectObjectWithCalendarOrTimeZone(temporalYearMonthLike);
options = ES.GetOptionsObject(options);

const calendar = GetSlot(this, CALENDAR);
const fieldNames = ES.CalendarFields(calendar, ['month', 'monthCode', 'year']);
const partialYearMonth = ES.PrepareTemporalFields(temporalYearMonthLike, fieldNames, 'partial');
let fields = ES.PrepareTemporalFields(this, fieldNames, []);
const partialYearMonth = ES.PrepareTemporalFields(temporalYearMonthLike, fieldNames, 'partial');
fields = ES.CalendarMergeFields(calendar, fields, partialYearMonth);
fields = ES.PrepareTemporalFields(fields, fieldNames, []);

options = ES.GetOptionsObject(options);

return ES.CalendarYearMonthFromFields(calendar, fields, options);
}
add(temporalDurationLike, options = undefined) {
Expand Down
4 changes: 2 additions & 2 deletions polyfill/lib/zoneddatetime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ export class ZonedDateTime {
throw new TypeError('invalid zoned-date-time-like');
}
ES.RejectObjectWithCalendarOrTimeZone(temporalZonedDateTimeLike);
options = ES.GetOptionsObject(options);

const calendar = GetSlot(this, CALENDAR);
const fieldNames = ES.CalendarFields(calendar, [
Expand All @@ -195,12 +196,11 @@ export class ZonedDateTime {
'year'
]);
ES.Call(ArrayPrototypePush, fieldNames, ['offset']);
const partialZonedDateTime = ES.PrepareTemporalFields(temporalZonedDateTimeLike, fieldNames, 'partial');
let fields = ES.PrepareTemporalFields(this, fieldNames, ['offset']);
const partialZonedDateTime = ES.PrepareTemporalFields(temporalZonedDateTimeLike, fieldNames, 'partial');
fields = ES.CalendarMergeFields(calendar, fields, partialZonedDateTime);
fields = ES.PrepareTemporalFields(fields, fieldNames, ['offset']);

options = ES.GetOptionsObject(options);
const disambiguation = ES.ToTemporalDisambiguation(options);
const offset = ES.ToTemporalOffset(options, 'prefer');

Expand Down
4 changes: 2 additions & 2 deletions spec/plaindate.html
Original file line number Diff line number Diff line change
Expand Up @@ -391,11 +391,11 @@ <h1>Temporal.PlainDate.prototype.with ( _temporalDateLike_ [ , _options_ ] )</h1
1. If Type(_temporalDateLike_) is not Object, then
1. Throw a *TypeError* exception.
1. Perform ? RejectObjectWithCalendarOrTimeZone(_temporalDateLike_).
1. Set _options_ to ? GetOptionsObject(_options_).
1. Let _calendar_ be _temporalDate_.[[Calendar]].
1. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
1. Let _partialDate_ be ? PrepareTemporalFields(_temporalDateLike_, _fieldNames_, ~partial~).
1. Set _options_ to ? GetOptionsObject(_options_).
1. Let _fields_ be ? PrepareTemporalFields(_temporalDate_, _fieldNames_, «»).
1. Let _partialDate_ be ? PrepareTemporalFields(_temporalDateLike_, _fieldNames_, ~partial~).
1. Set _fields_ to ? CalendarMergeFields(_calendar_, _fields_, _partialDate_).
1. Set _fields_ to ? PrepareTemporalFields(_fields_, _fieldNames_, «»).
1. Return ? CalendarDateFromFields(_calendar_, _fields_, _options_).
Expand Down
4 changes: 2 additions & 2 deletions spec/plaindatetime.html
Original file line number Diff line number Diff line change
Expand Up @@ -394,11 +394,11 @@ <h1>Temporal.PlainDateTime.prototype.with ( _temporalDateTimeLike_ [ , _options_
1. If Type(_temporalDateTimeLike_) is not Object, then
1. Throw a *TypeError* exception.
1. Perform ? RejectObjectWithCalendarOrTimeZone(_temporalDateTimeLike_).
1. Set _options_ to ? GetOptionsObject(_options_).
1. Let _calendar_ be _dateTime_.[[Calendar]].
1. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"hour"*, *"microsecond"*, *"millisecond"*, *"minute"*, *"month"*, *"monthCode"*, *"nanosecond"*, *"second"*, *"year"* »).
1. Let _partialDateTime_ be ? PrepareTemporalFields(_temporalDateTimeLike_, _fieldNames_, ~partial~).
1. Set _options_ to ? GetOptionsObject(_options_).
1. Let _fields_ be ? PrepareTemporalFields(_dateTime_, _fieldNames_, «»).
1. Let _partialDateTime_ be ? PrepareTemporalFields(_temporalDateTimeLike_, _fieldNames_, ~partial~).
1. Set _fields_ to ? CalendarMergeFields(_calendar_, _fields_, _partialDateTime_).
1. Set _fields_ to ? PrepareTemporalFields(_fields_, _fieldNames_, «»).
1. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_).
Expand Down
4 changes: 2 additions & 2 deletions spec/plainmonthday.html
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,11 @@ <h1>Temporal.PlainMonthDay.prototype.with ( _temporalMonthDayLike_ [ , _options_
1. If Type(_temporalMonthDayLike_) is not Object, then
1. Throw a *TypeError* exception.
1. Perform ? RejectObjectWithCalendarOrTimeZone(_temporalMonthDayLike_).
1. Set _options_ to ? GetOptionsObject(_options_).
1. Let _calendar_ be _monthDay_.[[Calendar]].
1. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
1. Let _partialMonthDay_ be ? PrepareTemporalFields(_temporalMonthDayLike_, _fieldNames_, ~partial~).
1. Set _options_ to ? GetOptionsObject(_options_).
1. Let _fields_ be ? PrepareTemporalFields(_monthDay_, _fieldNames_, «»).
1. Let _partialMonthDay_ be ? PrepareTemporalFields(_temporalMonthDayLike_, _fieldNames_, ~partial~).
1. Set _fields_ to ? CalendarMergeFields(_calendar_, _fields_, _partialMonthDay_).
1. Set _fields_ to ? PrepareTemporalFields(_fields_, _fieldNames_, «»).
1. Return ? CalendarMonthDayFromFields(_calendar_, _fields_, _options_).
Expand Down
2 changes: 1 addition & 1 deletion spec/plaintime.html
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,9 @@ <h1>Temporal.PlainTime.prototype.with ( _temporalTimeLike_ [ , _options_ ] )</h1
1. If Type(_temporalTimeLike_) is not Object, then
1. Throw a *TypeError* exception.
1. Perform ? RejectObjectWithCalendarOrTimeZone(_temporalTimeLike_).
1. Let _partialTime_ be ? ToTemporalTimeRecord(_temporalTimeLike_, ~partial~).
1. Set _options_ to ? GetOptionsObject(_options_).
1. Let _overflow_ be ? ToTemporalOverflow(_options_).
1. Let _partialTime_ be ? ToTemporalTimeRecord(_temporalTimeLike_, ~partial~).
1. If _partialTime_.[[Hour]] is not *undefined*, then
1. Let _hour_ be _partialTime_.[[Hour]].
1. Else,
Expand Down
10 changes: 5 additions & 5 deletions spec/plainyearmonth.html
Original file line number Diff line number Diff line change
Expand Up @@ -227,11 +227,11 @@ <h1>Temporal.PlainYearMonth.prototype.with ( _temporalYearMonthLike_ [ , _option
1. If Type(_temporalYearMonthLike_) is not Object, then
1. Throw a *TypeError* exception.
1. Perform ? RejectObjectWithCalendarOrTimeZone(_temporalYearMonthLike_).
1. Set _options_ to ? GetOptionsObject(_options_).
1. Let _calendar_ be _yearMonth_.[[Calendar]].
1. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"month"*, *"monthCode"*, *"year"* »).
1. Let _partialYearMonth_ be ? PrepareTemporalFields(_temporalYearMonthLike_, _fieldNames_, ~partial~).
1. Set _options_ to ? GetOptionsObject(_options_).
1. Let _fields_ be ? PrepareTemporalFields(_yearMonth_, _fieldNames_, «»).
1. Let _partialYearMonth_ be ? PrepareTemporalFields(_temporalYearMonthLike_, _fieldNames_, ~partial~).
1. Set _fields_ to ? CalendarMergeFields(_calendar_, _fields_, _partialYearMonth_).
1. Set _fields_ to ? PrepareTemporalFields(_fields_, _fieldNames_, «»).
1. Return ? CalendarYearMonthFromFields(_calendar_, _fields_, _options_).
Expand Down Expand Up @@ -611,12 +611,12 @@ <h1>
1. If ? CalendarEquals(_calendar_, _other_.[[Calendar]]) is *false*, throw a *RangeError* exception.
1. Let _settings_ be ? GetDifferenceSettings(_operation_, _options_, ~date~, &laquo; *"week"*, *"day"* &raquo;, *"month"*, *"year"*).
1. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"monthCode"*, *"year"* »).
1. Let _otherFields_ be ? PrepareTemporalFields(_other_, _fieldNames_, «»).
1. Perform ! CreateDataPropertyOrThrow(_otherFields_, *"day"*, *1*<sub>𝔽</sub>).
1. Let _otherDate_ be ? CalendarDateFromFields(_calendar_, _otherFields_).
1. Let _thisFields_ be ? PrepareTemporalFields(_yearMonth_, _fieldNames_, «»).
1. Perform ! CreateDataPropertyOrThrow(_thisFields_, *"day"*, *1*<sub>𝔽</sub>).
1. Let _thisDate_ be ? CalendarDateFromFields(_calendar_, _thisFields_).
1. Let _otherFields_ be ? PrepareTemporalFields(_other_, _fieldNames_, «»).
1. Perform ! CreateDataPropertyOrThrow(_otherFields_, *"day"*, *1*<sub>𝔽</sub>).
1. Let _otherDate_ be ? CalendarDateFromFields(_calendar_, _otherFields_).
1. Let _untilOptions_ be OrdinaryObjectCreate(*null*).
1. Perform ? CopyDataProperties(_untilOptions_, _settings_.[[Options]], « »).
1. Perform ! CreateDataPropertyOrThrow(_untilOptions_, *"largestUnit"*, _settings_.[[LargestUnit]]).
Expand Down
4 changes: 2 additions & 2 deletions spec/zoneddatetime.html
Original file line number Diff line number Diff line change
Expand Up @@ -581,14 +581,14 @@ <h1>Temporal.ZonedDateTime.prototype.with ( _temporalZonedDateTimeLike_ [ , _opt
1. If Type(_temporalZonedDateTimeLike_) is not Object, then
1. Throw a *TypeError* exception.
1. Perform ? RejectObjectWithCalendarOrTimeZone(_temporalZonedDateTimeLike_).
1. Set _options_ to ? GetOptionsObject(_options_).
1. Let _calendar_ be _zonedDateTime_.[[Calendar]].
1. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"hour"*, *"microsecond"*, *"millisecond"*, *"minute"*, *"month"*, *"monthCode"*, *"nanosecond"*, *"second"*, *"year"* »).
1. Append *"offset"* to _fieldNames_.
1. Let _partialZonedDateTime_ be ? PrepareTemporalFields(_temporalZonedDateTimeLike_, _fieldNames_, ~partial~).
1. Let _fields_ be ? PrepareTemporalFields(_zonedDateTime_, _fieldNames_, « *"offset"* »).
1. Let _partialZonedDateTime_ be ? PrepareTemporalFields(_temporalZonedDateTimeLike_, _fieldNames_, ~partial~).
1. Set _fields_ to ? CalendarMergeFields(_calendar_, _fields_, _partialZonedDateTime_).
1. Set _fields_ to ? PrepareTemporalFields(_fields_, _fieldNames_, « *"offset"* »).
1. Set _options_ to ? GetOptionsObject(_options_).
1. NOTE: The following steps read options and perform independent validation in alphabetical order (ToTemporalDisambiguation reads *"disambiguation"*, ToTemporalOffset reads *"offset"*, and InterpretTemporalDateTimeFields reads *"overflow"*).
1. Let _disambiguation_ be ? ToTemporalDisambiguation(_options_).
1. Let _offset_ be ? ToTemporalOffset(_options_, *"prefer"*).
Expand Down

0 comments on commit f35fc58

Please sign in to comment.