Skip to content

Commit

Permalink
Pass objects into user code after doing other things with them
Browse files Browse the repository at this point in the history
In the case where a property Get is performed on an object that also gets
passed into user code, we want to do the Get before the user code receives
the object. There was one place in the spec text where this was the other
way around.

After having been touched by user code, an object should only have its
internal slots read, or else it needs to be copied with
PrepareTemporalFields so that any getters that the user code installed are
called once each, in a defined order.

See: #1426
  • Loading branch information
ptomato committed Apr 9, 2021
1 parent 863692f commit 2b7197f
Show file tree
Hide file tree
Showing 22 changed files with 522 additions and 2 deletions.
2 changes: 1 addition & 1 deletion polyfill/lib/ecmascript.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1156,11 +1156,11 @@ export const ES = ObjectAssign({}, ES2020, {
return new TemporalPlainDate(year, month, day, calendar);
},
InterpretTemporalDateTimeFields: (calendar, fields, options) => {
let { hour, minute, second, millisecond, microsecond, nanosecond } = ES.ToTemporalTimeRecord(fields);
const date = ES.DateFromFields(calendar, fields, options);
const year = GetSlot(date, ISO_YEAR);
const month = GetSlot(date, ISO_MONTH);
const day = GetSlot(date, ISO_DAY);
let { hour, minute, second, millisecond, microsecond, nanosecond } = ES.ToTemporalTimeRecord(fields);
const overflow = ES.ToTemporalOverflow(options);
({ hour, minute, second, millisecond, microsecond, nanosecond } = ES.RegulateTime(
hour,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (C) 2021 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.duration.compare
info: |
sec-temporal.duration.compare step 4:
4. Let _relativeTo_ be ? ToRelativeTemporalObject(_options_).
sec-temporal-torelativetemporalobject step 4.g:
g. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_).
sec-temporal-interprettemporaldatetimefields steps 1–2:
1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_).
2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_).
includes: [temporalHelpers.js]
---*/

const calendar = TemporalHelpers.calendarMakeInvalidGettersTime();
const duration1 = new Temporal.Duration(1);
const duration2 = new Temporal.Duration(0, 12);
Temporal.Duration.compare(duration1, duration2, { relativeTo: { year: 2000, month: 1, day: 1, calendar } });
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (C) 2021 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.duration.prototype.add
info: |
sec-temporal.duration.prototype.add step 5:
5. Let _relativeTo_ be ? ToRelativeTemporalObject(_options_).
sec-temporal-torelativetemporalobject step 4.g:
g. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_).
sec-temporal-interprettemporaldatetimefields steps 1–2:
1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_).
2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_).
includes: [temporalHelpers.js]
---*/

const calendar = TemporalHelpers.calendarMakeInvalidGettersTime();
const duration1 = new Temporal.Duration(1);
const duration2 = new Temporal.Duration(0, 12);
duration1.add(duration2, { relativeTo: { year: 2000, month: 1, day: 1, calendar } });
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (C) 2021 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.duration.prototype.round
info: |
sec-temporal.duration.prototype.round step 19:
19. Let _relativeTo_ be ? ToRelativeTemporalObject(_options_).
sec-temporal-torelativetemporalobject step 4.g:
g. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_).
sec-temporal-interprettemporaldatetimefields steps 1–2:
1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_).
2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_).
includes: [temporalHelpers.js]
---*/

const calendar = TemporalHelpers.calendarMakeInvalidGettersTime();
const duration = new Temporal.Duration(1, 1, 1, 1, 1, 1, 1);
duration.round({ smallestUnit: 'months', relativeTo: { year: 2000, month: 1, day: 1, calendar } });
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (C) 2021 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.duration.prototype.subtract
info: |
sec-temporal.duration.prototype.subtract step 5:
5. Let _relativeTo_ be ? ToRelativeTemporalObject(_options_).
sec-temporal-torelativetemporalobject step 4.g:
g. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_).
sec-temporal-interprettemporaldatetimefields steps 1–2:
1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_).
2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_).
includes: [temporalHelpers.js]
---*/

const calendar = TemporalHelpers.calendarMakeInvalidGettersTime();
const duration1 = new Temporal.Duration(1);
const duration2 = new Temporal.Duration(0, 12);
duration1.subtract(duration2, { relativeTo: { year: 2000, month: 1, day: 1, calendar } });
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (C) 2021 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.duration.prototype.total
info: |
sec-temporal.duration.prototype.total step 4:
4. Let _relativeTo_ be ? ToRelativeTemporalObject(_options_).
sec-temporal-torelativetemporalobject step 4.g:
g. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_).
sec-temporal-interprettemporaldatetimefields steps 1–2:
1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_).
2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_).
includes: [temporalHelpers.js]
---*/

const calendar = TemporalHelpers.calendarMakeInvalidGettersTime();
const duration = new Temporal.Duration(1, 1, 1, 1, 1, 1, 1);
duration.total({ unit: 'seconds', relativeTo: { year: 2000, month: 1, day: 1, calendar } });
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (C) 2021 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.plaindatetime.compare
description: The time fields are read from the object before being passed to dateFromFields().
info: |
sec-temporal.plaindatetime.compare steps 1–2:
1. Set _one_ to ? ToTemporalDateTime(_one_).
2. Set _two_ to ? ToTemporalDateTime(_two_).
sec-temporal-totemporaldatetime step 2.e:
e. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_).
sec-temporal-interprettemporaldatetimefields steps 1–2:
1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_).
2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_).
includes: [temporalHelpers.js]
---*/

const calendar = TemporalHelpers.calendarMakeInfinityTime();
const result = Temporal.PlainDateTime.compare(
{ year: 2000, month: 5, day: 2, hour: 12, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321, calendar },
{ year: 2000, month: 5, day: 2, hour: 6, minute: 54, second: 32, millisecond: 123, microsecond: 456, nanosecond: 789, calendar },
);

// will be 0 if the time fields are coerced to their max values due to Infinity
assert.sameValue(result, 1, "comparison result");
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (C) 2021 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.plaindatetime.from
description: The time fields are read from the object before being passed to dateFromFields().
info: |
sec-temporal.plaindatetime.from step 3:
3. Return ? ToTemporalDateTime(_item_, _options_).
sec-temporal-totemporaldatetime step 2.e:
e. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_).
sec-temporal-interprettemporaldatetimefields steps 1–2:
1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_).
2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_).
includes: [temporalHelpers.js]
---*/

const calendar = TemporalHelpers.calendarMakeInfinityTime();
const datetime = Temporal.PlainDateTime.from({ year: 2000, month: 5, day: 2, hour: 12, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321, calendar });

assert.sameValue(datetime.hour, 12, "hour value");
assert.sameValue(datetime.minute, 34, "minute value");
assert.sameValue(datetime.second, 56, "second value");
assert.sameValue(datetime.millisecond, 987, "millisecond value");
assert.sameValue(datetime.microsecond, 654, "microsecond value");
assert.sameValue(datetime.nanosecond, 321, "nanosecond value");
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (C) 2021 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.plaindatetime.prototype.equals
description: The time fields are read from the object before being passed to dateFromFields().
info: |
sec-temporal.plaindatetime.prototype.equals step 3:
3. Set _other_ to ? ToTemporalDateTime(_other_).
sec-temporal-totemporaldatetime step 2.e:
e. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_).
sec-temporal-interprettemporaldatetimefields steps 1–2:
1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_).
2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_).
includes: [temporalHelpers.js]
---*/

const calendar = TemporalHelpers.calendarMakeInfinityTime();
const datetime = new Temporal.PlainDateTime(2021, 3, 31, 12, 34, 56, 987, 654, 321, calendar);
const result = datetime.equals({ year: 2021, month: 3, day: 31, hour: 12, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321, calendar });

assert(result, "time fields are not modified");
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (C) 2021 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.plaindatetime.prototype.since
description: The time fields are read from the object before being passed to dateFromFields().
info: |
sec-temporal.plaindatetime.prototype.since step 3:
3. Set _other_ to ? ToTemporalDateTime(_other_).
sec-temporal-totemporaldatetime step 2.e:
e. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_).
sec-temporal-interprettemporaldatetimefields steps 1–2:
1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_).
2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_).
includes: [temporalHelpers.js]
---*/

const calendar = TemporalHelpers.calendarMakeInfinityTime();
const datetime = new Temporal.PlainDateTime(2021, 3, 31, 12, 34, 56, 987, 654, 321);
const duration = datetime.since({ year: 2021, month: 3, day: 31, calendar });

assert.sameValue(duration.years, 0, "years value");
assert.sameValue(duration.months, 0, "months value");
assert.sameValue(duration.weeks, 0, "weeks value");
assert.sameValue(duration.days, 0, "days value");
assert.sameValue(duration.hours, 12, "hours value");
assert.sameValue(duration.minutes, 34, "minutes value");
assert.sameValue(duration.seconds, 56, "seconds value");
assert.sameValue(duration.milliseconds, 987, "milliseconds value");
assert.sameValue(duration.microseconds, 654, "microseconds value");
assert.sameValue(duration.nanoseconds, 321, "nanoseconds value");
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (C) 2021 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.plaindatetime.prototype.until
description: The time fields are read from the object before being passed to dateFromFields().
info: |
sec-temporal.plaindatetime.prototype.until step 3:
3. Set _other_ to ? ToTemporalDateTime(_other_).
sec-temporal-totemporaldatetime step 2.e:
e. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_).
sec-temporal-interprettemporaldatetimefields steps 1–2:
1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_).
2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_).
includes: [temporalHelpers.js]
---*/

const calendar = TemporalHelpers.calendarMakeInfinityTime();
const datetime = new Temporal.PlainDateTime(2021, 3, 31, 12, 34, 56, 987, 654, 321);
const duration = datetime.until({ year: 2021, month: 3, day: 31, calendar });

assert.sameValue(duration.years, 0, "years value");
assert.sameValue(duration.months, 0, "months value");
assert.sameValue(duration.weeks, 0, "weeks value");
assert.sameValue(duration.days, 0, "days value");
assert.sameValue(duration.hours, -12, "hours value");
assert.sameValue(duration.minutes, -34, "minutes value");
assert.sameValue(duration.seconds, -56, "seconds value");
assert.sameValue(duration.milliseconds, -987, "milliseconds value");
assert.sameValue(duration.microseconds, -654, "microseconds value");
assert.sameValue(duration.nanoseconds, -321, "nanoseconds value");
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (C) 2021 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.plaindatetime.prototype.with
description: The time fields are read from the object before being passed to dateFromFields().
info: |
sec-temporal.plaindatetime.prototype.with step 15:
15. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_).
sec-temporal-interprettemporaldatetimefields steps 1–2:
1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_).
2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_).
includes: [temporalHelpers.js]
---*/

const calendar = TemporalHelpers.calendarMakeInfinityTime();
const datetime = new Temporal.PlainDateTime(2021, 3, 31, 12, 34, 56, 987, 654, 321, calendar);
const newDatetime = datetime.with({ year: 2022 });

assert.sameValue(newDatetime.hour, 12, "hour value");
assert.sameValue(newDatetime.minute, 34, "minute value");
assert.sameValue(newDatetime.second, 56, "second value");
assert.sameValue(newDatetime.millisecond, 987, "millisecond value");
assert.sameValue(newDatetime.microsecond, 654, "microsecond value");
assert.sameValue(newDatetime.nanosecond, 321, "nanosecond value");
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (C) 2021 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.timezone.prototype.getinstantfor
description: The time fields are read from the object before being passed to dateFromFields().
info: |
sec-temporal.timezone.prototype.getinstantfor step 3:
3. Set _dateTime_ to ? ToTemporalDateTime(_dateTime_).
sec-temporal-totemporaldatetime step 2.e:
e. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_).
sec-temporal-interprettemporaldatetimefields steps 1–2:
1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_).
2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_).
includes: [temporalHelpers.js]
---*/

const timezone = new Temporal.TimeZone("UTC");
const calendar = TemporalHelpers.calendarMakeInfinityTime();
const result = timezone.getInstantFor({ year: 1970, month: 1, day: 1, calendar });

assert.sameValue(result.epochNanoseconds, 0n, "epochNanoseconds result");
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (C) 2021 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.timezone.prototype.getpossibleinstantsfor
description: The time fields are read from the object before being passed to dateFromFields().
info: |
sec-temporal.timezone.prototype.getpossibleinstantsfor step 3:
3. Set _dateTime_ to ? ToTemporalDateTime(_dateTime_).
sec-temporal-totemporaldatetime step 2.e:
e. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_).
sec-temporal-interprettemporaldatetimefields steps 1–2:
1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_).
2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_).
includes: [temporalHelpers.js]
---*/

const timezone = new Temporal.TimeZone("UTC");
const calendar = TemporalHelpers.calendarMakeInfinityTime();
const result = timezone.getPossibleInstantsFor({ year: 1970, month: 1, day: 1, calendar });

assert.sameValue(result.length, 1, "result array length");
assert.sameValue(result[0].epochNanoseconds, 0n, "epochNanoseconds result");
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (C) 2021 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.zoneddatetime.compare
description: The time fields are read from the object before being passed to dateFromFields().
info: |
sec-temporal.zoneddatetime.compare steps 1–2:
1. Set _one_ to ? ToTemporalZonedDateTime(_one_).
2. Set _two_ to ? ToTemporalZonedDateTime(_two_).
sec-temporal-totemporalzoneddatetime step 2.j:
j. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_).
sec-temporal-interprettemporaldatetimefields steps 1–2:
1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_).
2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_).
includes: [temporalHelpers.js]
---*/

const calendar = TemporalHelpers.calendarMakeInfinityTime();
const result = Temporal.ZonedDateTime.compare(
{ year: 2000, month: 5, day: 2, hour: 12, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321, timeZone: "UTC", calendar },
{ year: 2000, month: 5, day: 2, hour: 6, minute: 54, second: 32, millisecond: 123, microsecond: 456, nanosecond: 789, timeZone: "UTC", calendar },
);

// will be 0 if the time fields are coerced to their max values due to Infinity
assert.sameValue(result, 1, "comparison result");
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (C) 2021 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.zoneddatetime.from
description: The time fields are read from the object before being passed to dateFromFields().
info: |
sec-temporal.zoneddatetime.from step 3:
3. Return ? ToTemporalDateTime(_item_, _options_).
sec-temporal-totemporalzoneddatetime step 2.j:
j. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _options_).
sec-temporal-interprettemporaldatetimefields steps 1–2:
1. Let _timeResult_ be ? ToTemporalTimeRecord(_fields_).
2. Let _temporalDate_ be ? DateFromFields(_calendar_, _fields_, _options_).
includes: [temporalHelpers.js]
---*/

const calendar = TemporalHelpers.calendarMakeInfinityTime();
const datetime = Temporal.ZonedDateTime.from({ year: 2000, month: 5, day: 2, hour: 12, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321, timeZone: "UTC", calendar });

assert.sameValue(datetime.hour, 12, "hour value");
assert.sameValue(datetime.minute, 34, "minute value");
assert.sameValue(datetime.second, 56, "second value");
assert.sameValue(datetime.millisecond, 987, "millisecond value");
assert.sameValue(datetime.microsecond, 654, "microsecond value");
assert.sameValue(datetime.nanosecond, 321, "nanosecond value");
Loading

0 comments on commit 2b7197f

Please sign in to comment.