| 488 | impl Hashable for PyUnion { |
| 489 | #[inline] |
| 490 | fn hash(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<hash::PyHash> { |
| 491 | // If there are any unhashable args from creation time, the union is unhashable |
| 492 | if let Some(ref unhashable_args) = zelf.unhashable_args { |
| 493 | let n = unhashable_args.len(); |
| 494 | // Try to hash each previously unhashable arg to get an error |
| 495 | for arg in unhashable_args.iter() { |
| 496 | arg.hash(vm)?; |
| 497 | } |
| 498 | // All previously unhashable args somehow became hashable |
| 499 | // But still raise an error to maintain consistent hashing |
| 500 | return Err(vm.new_type_error(format!( |
| 501 | "union contains {} unhashable element{}", |
| 502 | n, |
| 503 | if n > 1 { "s" } else { "" } |
| 504 | ))); |
| 505 | } |
| 506 | |
| 507 | // If we have a stored frozenset of hashable args, use that |
| 508 | if let Some(ref hashable_args) = zelf.hashable_args { |
| 509 | return PyFrozenSet::hash(hashable_args, vm); |
| 510 | } |
| 511 | |
| 512 | // Fallback: compute hash from args |
| 513 | let mut args_to_hash = Vec::new(); |
| 514 | for arg in &*zelf.args { |
| 515 | match arg.hash(vm) { |
| 516 | Ok(_) => args_to_hash.push(arg.clone()), |
| 517 | Err(e) => return Err(e), |
| 518 | } |
| 519 | } |
| 520 | let set = PyFrozenSet::from_iter(vm, args_to_hash.into_iter())?; |
| 521 | PyFrozenSet::hash(&set.into_ref(&vm.ctx), vm) |
| 522 | } |
| 523 | } |
| 524 | |
| 525 | impl GetAttr for PyUnion { |