Repository: astral-sh/ruff
File: crates/ty_python_semantic/src/types/call/arguments.rs (Rust)

Code before:
                            .map(|types| Type::tuple(TupleType::heterogeneous(db, types)))
                            .collect::<Vec<_>>();

                        if expanded.len() == 1 {
                            // There are no elements in the tuple type that can be expanded.
                            None
                        } else {
                            Some(expanded)
                        }
                    }
                    Tuple::Variable(_) => None,
                };
            }

            if let Some(enum_members) = enum_member_literals(db, class.class_literal(db), None) {
                return Some(enum_members.collect());
            }

            None
        }
        Type::Union(union) => Some(union.elements(db).to_vec()),
        // For type aliases, expand the underlying value type.
        Type::TypeAlias(alias) => expand_type(db, alias.value_type(db)),
        // We don't handle `type[A | B]` here because it's already stored in the expanded form
        // i.e., `type[A] | type[B]` which is handled by the `Type::Union` case.
        _ => None,
    }
}

#[cfg(test)]
mod tests {
    use crate::db::tests::setup_db;
    use crate::types::tuple::TupleType;
    use crate::types::{KnownClass, ManualPEP695TypeAliasType, Type, TypeAliasType, UnionType};
    use ruff_python_ast as ast;

    use super::expand_type;

    #[test]
    fn expand_union_type() {
        let db = setup_db();
        let types = [
            KnownClass::Int.to_instance(&db),
            KnownClass::Str.to_instance(&db),
            KnownClass::Bytes.to_instance(&db),
        ];
        let union_type = UnionType::from_elements(&db, types);
        let expanded = expand_type(&db, union_type).unwrap();
        assert_eq!(expanded.len(), types.len());
        assert_eq!(expanded, types);
    }

Review comment (suggestion):
```suggestion
                                .map(|types| Type::heterogeneous_tuple(db, types))
```

Code after:
            if let Some(spec) = instance.tuple_spec(db) {
                return match &*spec {
                    Tuple::Fixed(fixed_length_tuple) => {
                        // Pre-expand each element and compute the total Cartesian product size.
                        // Bail out early if the product would exceed `MAX_TUPLE_EXPANSION` to
                        // avoid exponential blowup (e.g. a 37-element tuple with 2-element
                        // unions would produce 2^37 types).
                        let per_element: Vec<_> = fixed_length_tuple
                            .iter_all_elements()
                            .map(|element| {
                                expand_type(db, element).unwrap_or_else(|| vec![element])
                            })
                            .collect();

                        let product_size: usize = per_element
                            .iter()
                            .try_fold(1usize, |acc, v| acc.checked_mul(v.len()))
                            .unwrap_or(usize::MAX);

                        if product_size <= 1 || product_size > MAX_TUPLE_EXPANSION {
                            None
                        } else {
                            let expanded = per_element
                                .into_iter()
                                .multi_cartesian_product()
                                .map(|types| Type::tuple(TupleType::heterogeneous(db, types)))
                                .collect::<Vec<_>>();
                            Some(expanded)
                        }
                    }
                    Tuple::Variable(_) => None,
                };
            }

            if let Some(enum_members) = enum_member_literals(db, class.class_literal(db), None) {
                return Some(enum_members.collect());
            }

            None
        }
        Type::Union(union) => Some(union.elements(db).to_vec()),
        // For type aliases, expand the underlying value type.
        Type::TypeAlias(alias) => expand_type(db, alias.value_type(db)),
        // We don't handle `type[A | B]` here because it's already stored in the expanded form
        // i.e., `type[A] | type[B]` which is handled by the `Type::Union` case.
        _ => None,
    }
}

#[cfg(test)]
mod tests {