[ty] hash-cons `UseDefMap` fields (#23283)
## Summary
Implement hash-consing for several fields in `UseDefMap` to reduce
memory usage.
The rationale for this optimization is the size and high duplication
rate of the structs used in `UseDefMap`. The size of each struct is:
* Bindings: 40
* PlaceState: 64
* ReachableDefinitions: 64
* EnclosingSnapshot: 40
These elements are stored within `IndexVec` where duplication of
elements can occur.
For example, taking these statistics (duplication rate) with hydra-zen
yields the following:
- bindings_by_use: 65.13%
- end_of_scope_members: 57.37%
- enclosing_snapshots: 57.18%
- reachable_definitions_by_member: 34.58%
- declarations_by_binding: 32.70%
- bindings_by_definition: 27.84%
- end_of_scope_symbols: 21.25%
- reachable_definitions_by_symbol: 15.70%
The disparity in duplication rates between symbols and members was a bit
surprising, but can be explained as follows: `obj.attr` and `obj["k"]`
might be tracked, but often end up in a similar undefined/unbound state,
leading to a large number of identical `PlaceState` instances.
This PR implements hash-consing for these fields. Specifically, each
`IndexVec` for these fields will only store IDs for each struct, and the
actual struct instances will be stored in another `IndexVec` without
duplication.
According to the memory usage report, this change reduced the size of
`SemanticIndex` by about 10%.
## Performance analysis
What this PR is trying to do involves a trade-off between time
complexity and space complexity.
In #23201, I aimed to achieve a more significant reduction in memory
consumption by interning `Bindings`, but this resulted in a major
regression in time performance, so I decided to manually intern only
items that seemed to have a high effect.
This PR change is not very effective for microbenchmarks, and rather
adds a time cost (due to hash calculations). However, looking at the
trends in the memory report, it seems that for large codebases, it can
achieve significant memory savings with relatively little overhead. The
larger the `UseDefMap`, the greater the reduction, so I think it's worth
to do this.
The commit that achieved the greatest memory consumption reduction in
this PR was b9d067abcc4da4ce94bae5843b14416c2ed282b6, but it was
reverted because it exceeded the threshold for codspeed microbenchmarks.
There was almost no impact on walltime benchmarks (in fact, some even
showed slight improvements).
## Test Plan
N/A