[ty] don't iterate over a hashset (#21649)

## Summary

This caused "deterministic but chaotic" ordering of some intersection
types in diagnostics. When calling a union, we infer the argument type
once per matching parameter type, intersecting the inferred types for
the argument expression, and we did that in an unpredictable order.

We do need a hashset here for de-duplication. Sometimes we call large
unions where the type for a given parameter is the same across the
union, we should infer the argument once per parameter type, not once
per union element. So use an `FxIndexSet` instead of an `FxHashSet`.

## Test Plan

With this change, switching between `main` and
https://github.com/astral-sh/ruff/pull/21646 no longer changes the
ordering of the intersection type in the test in
cca3a8045d
This commit is contained in:
Carl Meyer
2025-11-26 16:39:49 -08:00
committed by GitHub
parent e2e21508dc
commit e0f3a064b9

View File

@@ -6894,10 +6894,14 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
// Infer the type of each argument once with each distinct parameter type as type context.
let parameter_types = overloads_with_binding
.iter()
.filter_map(|(overload, binding)| parameter_type(overload, binding))
.collect::<FxHashSet<_>>();
.filter_map(|(overload, binding)| parameter_type(overload, binding));
let mut seen = FxHashSet::default();
for parameter_type in parameter_types {
if !seen.insert(parameter_type) {
continue;
}
let inferred_ty =
self.infer_expression(ast_argument, TypeContext::new(Some(parameter_type)));