Fuses multiple `Union` operators into one. Nested negated unions are merged into the parent one by pushing the Negate to all their inputs.
(relation: &mut MirRelationExpr)
| 50 | /// Nested negated unions are merged into the parent one by pushing |
| 51 | /// the Negate to all their inputs. |
| 52 | pub fn action(relation: &mut MirRelationExpr) { |
| 53 | use MirRelationExpr::*; |
| 54 | if let Union { base, inputs } = relation { |
| 55 | let can_fuse = iter::once(&**base).chain(&*inputs).any(|input| -> bool { |
| 56 | match input { |
| 57 | Union { .. } => true, |
| 58 | Negate { input } => matches!(**input, Union { .. }), |
| 59 | _ => false, |
| 60 | } |
| 61 | }); |
| 62 | if can_fuse { |
| 63 | let mut new_inputs: Vec<MirRelationExpr> = vec![]; |
| 64 | for input in iter::once(base.as_mut()).chain(inputs) { |
| 65 | let input = input.take_dangerous(); |
| 66 | match input { |
| 67 | Union { base, inputs } => { |
| 68 | new_inputs.push(*base); |
| 69 | new_inputs.extend(inputs); |
| 70 | } |
| 71 | Negate { input } if matches!(*input, Union { .. }) => { |
| 72 | if let Union { base, inputs } = *input { |
| 73 | new_inputs.push(base.negate()); |
| 74 | new_inputs.extend(inputs.into_iter().map(|x| x.negate())); |
| 75 | } else { |
| 76 | unreachable!() |
| 77 | } |
| 78 | } |
| 79 | _ => new_inputs.push(input), |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | // Pushing down negations might enable further Negate fusion. |
| 84 | for new_input in new_inputs.iter_mut() { |
| 85 | crate::fusion::negate::Negate::action(new_input); |
| 86 | } |
| 87 | |
| 88 | // A valid relation type is only needed for empty unions, but an existing union |
| 89 | // is guaranteed to be non-empty given that it always has at least a base branch. |
| 90 | assert!(!new_inputs.is_empty()); |
| 91 | *relation = MirRelationExpr::union_many(new_inputs, ReprRelationType::empty()); |
| 92 | } |
| 93 | } |
| 94 | } |
| 95 | } |
no test coverage detected