Skip to content

Conversation

@Manishearth
Copy link
Contributor

@Manishearth Manishearth commented Nov 25, 2025

Fixes #635

Updates to tc39/proposal-temporal#3172

This passes the test, but it fails other tests. The problem is probably that IncrementRounder isn't written in terms of r1 and r2. @nekevss, I don't understand the full purpose of IncrementRounder being written the way it is: mind having a look?

The new spec text changes how r1 and r2 are computed, and they're passed down to IncrementRounder in the spec but not the code, so I assume that IncrementRounder is recomputing them somehow from the inputs.

I wrote this to not use IncrementRounder. I'm not 100% sure if the implementation is correct when it comes to how it handles mathematical values.

@Manishearth Manishearth requested a review from nekevss November 25, 2025 02:45
@Manishearth Manishearth marked this pull request as draft November 25, 2025 02:45
@Manishearth
Copy link
Contributor Author

This now passes tests, but I'm not entirely sure of the impl

@Manishearth
Copy link
Contributor Author

Manishearth commented Nov 25, 2025

This fails other tests (due to hitting assertions, I think)

=== test262/built-ins/Temporal/PlainDate/prototype/since/roundingincrement ===
--- stdout ---
test/test262/data/test/built-ins/Temporal/PlainDate/prototype/since/roundingincrement.js:15: Error: Temporal error: Internal error: .
  later.since(earlier, { smallestUnit: "years", roundingIncrement: 4, roundingMode: "halfExpand" }),
        ^
Error: Temporal error: Internal error: .
    at PlainDate.since (<anonymous>)
    at test/test262/data/test/built-ins/Temporal/PlainDate/prototype/since/roundingincrement.js:15:9
Command: out/x64.release/d8 --test test/test262/data/harness/sta.js test/test262/data/harness/assert.js test/test262/harness-adapt.js test/test262/data/harness/temporalHelpers.js test/test262/data/test/built-ins/Temporal/PlainDate/prototype/since/roundingincrement.js --random-seed=1623281705 --nohard-abort --ignore-unhandled-promises --harmony-temporal --no-arguments
=== test262/built-ins/Temporal/PlainDate/prototype/since/roundingincrement ===
--- stdout ---
test/test262/data/test/built-ins/Temporal/PlainDate/prototype/since/roundingincrement.js:15: Error: Temporal error: Internal error: .
  later.since(earlier, { smallestUnit: "years", roundingIncrement: 4, roundingMode: "halfExpand" }),
        ^
Error: Temporal error: Internal error: .
    at PlainDate.since (<anonymous>)
    at test/test262/data/test/built-ins/Temporal/PlainDate/prototype/since/roundingincrement.js:15:9
Command: out/x64.release/d8 --test test/test262/data/harness/sta.js test/test262/data/harness/assert.js test/test262/harness-adapt.js test/test262/data/harness/temporalHelpers.js test/test262/data/test/built-ins/Temporal/PlainDate/prototype/since/roundingincrement.js --random-seed=1623281705 --nohard-abort --use-strict --ignore-unhandled-promises --harmony-temporal --no-arguments
=== test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-as-expected ===
--- stdout ---
test/test262/data/test/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-as-expected.js:14: Error: Temporal error: Internal error: .
const laterSinceYear = later.since(earlier, { smallestUnit: "years", roundingIncrement: 4, roundingMode: "halfExpand" });
                             ^
Error: Temporal error: Internal error: .
    at PlainYearMonth.since (<anonymous>)
    at test/test262/data/test/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-as-expected.js:14:30
Command: out/x64.release/d8 --test test/test262/data/harness/sta.js test/test262/data/harness/assert.js test/test262/harness-adapt.js test/test262/data/harness/temporalHelpers.js test/test262/data/test/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-as-expected.js --random-seed=1623281705 --nohard-abort --ignore-unhandled-promises --harmony-temporal --no-arguments
=== test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-wrong-type ===
--- stdout ---
test/test262/data/test/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-wrong-type.js:22: Error: Temporal error: Internal error: .
  (roundingIncrement) => later.since(earlier, { roundingIncrement }),
                               ^
Error: Temporal error: Internal error: .
    at PlainYearMonth.since (<anonymous>)
    at test/test262/data/test/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-wrong-type.js:22:32
    at Object.checkRoundingIncrementOptionWrongType (test/test262/data/harness/temporalHelpers.js:509:26)
    at test/test262/data/test/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-wrong-type.js:21:17
Command: out/x64.release/d8 --test test/test262/data/harness/sta.js test/test262/data/harness/assert.js test/test262/harness-adapt.js test/test262/data/harness/compareArray.js test/test262/data/harness/temporalHelpers.js test/test262/data/test/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-wrong-type.js --random-seed=1623281705 --nohard-abort --ignore-unhandled-promises --harmony-temporal --no-arguments
=== test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-as-expected ===
--- stdout ---
test/test262/data/test/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-as-expected.js:14: Error: Temporal error: Internal error: .
const laterSinceYear = later.since(earlier, { smallestUnit: "years", roundingIncrement: 4, roundingMode: "halfExpand" });
                             ^
Error: Temporal error: Internal error: .
    at PlainYearMonth.since (<anonymous>)
    at test/test262/data/test/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-as-expected.js:14:30
Command: out/x64.release/d8 --test test/test262/data/harness/sta.js test/test262/data/harness/assert.js test/test262/harness-adapt.js test/test262/data/harness/temporalHelpers.js test/test262/data/test/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-as-expected.js --random-seed=1623281705 --nohard-abort --use-strict --ignore-unhandled-promises --harmony-temporal --no-arguments
=== test262/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-wrong-type ===
--- stdout ---
test/test262/data/test/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-wrong-type.js:22: Error: Temporal error: Internal error: .
  (roundingIncrement) => later.since(earlier, { roundingIncrement }),
                               ^
Error: Temporal error: Internal error: .
    at PlainYearMonth.since (<anonymous>)
    at test/test262/data/test/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-wrong-type.js:22:32
    at Object.checkRoundingIncrementOptionWrongType (test/test262/data/harness/temporalHelpers.js:509:26)
    at test/test262/data/test/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-wrong-type.js:21:17
Command: out/x64.release/d8 --test test/test262/data/harness/sta.js test/test262/data/harness/assert.js test/test262/harness-adapt.js test/test262/data/harness/compareArray.js test/test262/data/harness/temporalHelpers.js test/test262/data/test/built-ins/Temporal/PlainYearMonth/prototype/since/roundingincrement-wrong-type.js --random-seed=1623281705 --nohard-abort --use-strict --ignore-unhandled-promises --harmony-temporal --no-arguments
=== test262/built-ins/Temporal/ZonedDateTime/prototype/since/roundingincrement-addition-out-of-range ===
--- stdout ---
test/test262/data/harness/assert.js:95: Test262Error: ending bound of 1e8 + 1 days is out of range when added to 1970-01-01 Expected a RangeError but got a Error
      throw new Test262Error(message);
      ^
Command: out/x64.release/d8 --test test/test262/data/harness/sta.js test/test262/data/harness/assert.js test/test262/harness-adapt.js test/test262/data/harness/temporalHelpers.js test/test262/data/test/built-ins/Temporal/ZonedDateTime/prototype/since/roundingincrement-addition-out-of-range.js --random-seed=1623281705 --nohard-abort --ignore-unhandled-promises --harmony-temporal --no-arguments
=== test262/built-ins/Temporal/ZonedDateTime/prototype/since/roundingincrement-addition-out-of-range ===
--- stdout ---
test/test262/data/harness/assert.js:95: Test262Error: ending bound of 1e8 + 1 days is out of range when added to 1970-01-01 Expected a RangeError but got a Error
      throw new Test262Error(message);
      ^
Command: out/x64.release/d8 --test test/test262/data/harness/sta.js test/test262/data/harness/assert.js test/test262/harness-adapt.js test/test262/data/harness/temporalHelpers.js test/test262/data/test/built-ins/Temporal/ZonedDateTime/prototype/since/roundingincrement-addition-out-of-range.js --random-seed=1623281705 --nohard-abort --use-strict --ignore-unhandled-promises --harmony-temporal --no-arguments
=== test262/built-ins/Temporal/ZonedDateTime/prototype/until/roundingincrement-addition-out-of-range ===
--- stdout ---
test/test262/data/harness/assert.js:95: Test262Error: ending bound of -1e8 - 1 days is out of range when added to 1970-01-01 Expected a RangeError but got a Error
      throw new Test262Error(message);
      ^
Command: out/x64.release/d8 --test test/test262/data/harness/sta.js test/test262/data/harness/assert.js test/test262/harness-adapt.js test/test262/data/harness/temporalHelpers.js test/test262/data/test/built-ins/Temporal/ZonedDateTime/prototype/until/roundingincrement-addition-out-of-range.js --random-seed=1623281705 --nohard-abort --ignore-unhandled-promises --harmony-temporal --no-arguments
=== test262/built-ins/Temporal/ZonedDateTime/prototype/until/roundingincrement-addition-out-of-range ===
--- stdout ---
test/test262/data/harness/assert.js:95: Test262Error: ending bound of -1e8 - 1 days is out of range when added to 1970-01-01 Expected a RangeError but got a Error
      throw new Test262Error(message);
      ^
Command: out/x64.release/d8 --test test/test262/data/harness/sta.js test/test262/data/harness/assert.js test/test262/harness-adapt.js test/test262/data/harness/temporalHelpers.js test/test262/data/test/built-ins/Temporal/ZonedDateTime/prototype/until/roundingincrement-addition-out-of-range.js --random-seed=1623281705 --nohard-abort --use-strict --ignore-unhandled-promises --harmony-temporal --no-arguments

===

Copy link
Member

@nekevss nekevss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have a couple notes after taking a glance.

Are you still looking into the failures mentioned above?

// 7. Let r1 be nudgeWindow.[[R1]].
// 8. Let r2 be nudgeWindow.[[R2]].
// 9. Set startEpochNs to nudgeWindow.[[StartEpochNs]].
// 10. Set endEpochNs to nudgeWindow.[[StartEpochNs]].
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, spec bug?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tc39/proposal-temporal#3191 - should have been caught in review, but anba caught it a bit later

(dest_epoch_ns - start_epoch_ns.0) as f64 / (end_epoch_ns.0 - start_epoch_ns.0) as f64;
// 14. Let progress be (destEpochNs - startEpochNs) / (endEpochNs - startEpochNs).
// 15. Let total be r1 + progress × increment × sign.
let progress = (dest_epoch_ns.0 - start_epoch_ns.0) as f64
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: this actually may be a candidate for using the Fraction type to compute


impl UnsignedRoundingMode {
/// <https://tc39.es/proposal-temporal/#sec-applyunsignedroundingmode>
pub(crate) fn apply(self, x: f64, r1: i128, r2: i128) -> i128 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: I think at the point that we are passing x as a f64, we should just pass r1 and r2 as a f64 as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't, because r1 and r2 are the actual returned values, and that would potentially change the produced mathematical value.

On the other hand, the only thing that matters about x is which side of r1 + r2 / 2 it is. That's easier to get right.

We should probably use a Fraction type.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't, because r1 and r2 are the actual returned values, and that would potentially change the produced mathematical value.

Ah shoot, true.

On the other hand, the only thing that matters about x is which side of r1 + r2 / 2 it is. That's easier to get right.

Yeah, that's what IncrementRounder was relying on.

temporal_assert!(r1.abs() as f64 <= total.abs() && total.abs() < r2.abs() as f64);
// b. Let roundedUnit be ApplyUnsignedRoundingMode(abs(total), abs(r1), abs(r2), unsignedRoundingMode).
// TODO: what happens to r2 here?
unsigned_rounding_mode.apply(total.abs(), r1.abs(), r2.abs())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, huh. Yeah, it'd probably be worth taking a second pass at rounding given some of the changes to the specification.

I'd really prefer to stay away from f64 if possible, but it might not be with all the changes that have been made to the spec since this was first written.

}
}

impl UnsignedRoundingMode {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: It would be nice to have some unit tests for this.

@Manishearth
Copy link
Contributor Author

Are you still looking into the failures mentioned above?

No, but they should be replicable by copying the tests.

@Manishearth
Copy link
Contributor Author

The failures were due to a missing <=. Fixed.

@Manishearth
Copy link
Contributor Author

And that fixes the crashes. Would still like to see if this can be written without floats, but I don't have time to do that myself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement new Nudge changes

3 participants