rust-lang / rustfmt

Format Rust code
https://rust-lang.github.io/rustfmt/
Apache License 2.0
6.05k stars 888 forks source link

repair Ord for UseSegment #6375

Closed ajewellamz closed 3 weeks ago

ajewellamz commented 1 month ago

Fixes https://github.com/rust-lang/rustfmt/issues/6333

Ord for UseSegment was not Transitive, causing user-provided comparison function does not correctly implement a total order panic.

e.g. for

let A = DafnyType let B = _System let C = truncate

A < B B < C but A > C

ytmimi commented 1 month ago

@ajewellamz Thanks for looking into this! Can you briefly explain how your fix addresses the issue?

ajewellamz commented 1 month ago

In the example above, the problem was that (A, C) was compared with the special case logic, but (A,B) and (B,C) were not. This is why the comparison operator was not transitive.

That is, segments that began with a character that was neither lower nor upper fell into an inconsistent gray area.

Said another way, A was CamelCase when compared to C but snake_case when compared to B.

Switching from is_lower to !is_upper changes that, A is always CamelCase, regardless of what it's being compared to.

ytmimi commented 4 weeks ago

So it was mostly an issue with special characters like _ that are neither uppercase nor lowercase? It doesn't look like any of the existing test cases changed, but I'm wondering if this change has the potential to change the current sort behavior?

ajewellamz commented 4 weeks ago

If all segments start with a letter, then there is no change.

If there is a segment that does not start with a letter, then the current behavior is indeterminate, and often results in a panic! (because Ord is not transitive) so we need a change.

Yes, it has the potential to change the current sort behavior, but with the current code, running rustfmt in a slightly different context also has potential to change the current sort behavior.

ajewellamz commented 3 weeks ago

So.... is there something more I can do? Our build and deployment processes are kinda blocked, because rustfmt crashes.

ytmimi commented 3 weeks ago

Yes, it has the potential to change the current sort behavior, but with the current code, running rustfmt in a slightly different context also has potential to change the current sort behavior.

Could you elaborate on which cases would potentially be changed? Also, what do you mean when you say running rustfmt in different contexts could change things?

So.... is there something more I can do?

Adding a test case would be great. Especially if you can think of cases where the new sort behavior differs from what we used to have. You can add a new test case by creating a .rs file to tests/target.

ajewellamz commented 3 weeks ago

If there are segments that don't begin with a letter, the current behavior is undefined, because the comparator is not transitive. This is what I mean by "could change", and why rustfmt will panic on some input, like that in https://github.com/rust-lang/rustfmt/issues/6333

I haven't found a case where rustfmt produces unexpected results but doesn't crash.

I've added tests/target/issue-6333.rs, but I might be confused about something, because cargo test passes but cargo run --bin rustfmt -- --check tests/target/issue-6333.rs fails.

ytmimi commented 3 weeks ago

You may need to add a config comment to the top of your test file to specify style_edition=2015 like // rustfmt-style_edition: 2015. In rustfmt's own rustfmt.toml file it's configured to uses the newer and still unstable style_edition=2024 by default, which I don't think has the same transitive issues.

ytmimi commented 3 weeks ago

We changed the sort order in style_edition=2024 to match the new sorting rules established by the style guide.

ajewellamz commented 3 weeks ago

Even with // rustfmt-style_edition: 2015 at the top of the file, I can't get cargo test and cargo run --bin rustfmt to agree.

ytmimi commented 3 weeks ago

// rustfmt-style_edition: 2015 will only work in the context of rustfmt tests. Outside of the test suite it's treated as a normal comment.

Can you try running cargo run --bin rustfmt -- --config=style_edition=2015

ajewellamz commented 3 weeks ago

Thanks. With --config=style_edition=2015, cargo test and cargo run --bin rustfmt agree.