diff --git a/hugr-passes/src/composable.rs b/hugr-passes/src/composable.rs index 41bdc628bd..6b11bf97ab 100644 --- a/hugr-passes/src/composable.rs +++ b/hugr-passes/src/composable.rs @@ -315,18 +315,6 @@ where } } -// Note remove when deprecated constant_fold_pass / remove_dead_funcs are removed -pub(crate) fn validate_if_test, H: HugrMut>( - pass: P, - hugr: &mut H, -) -> Result> { - if cfg!(test) { - ValidatingPass::new(pass).run(hugr) - } else { - Ok(pass.run(hugr)?) - } -} - #[cfg(test)] pub(crate) mod test { use hugr_core::ops::Value; diff --git a/hugr-passes/src/const_fold.rs b/hugr-passes/src/const_fold.rs index 310c5c3b35..8c154fd6a3 100644 --- a/hugr-passes/src/const_fold.rs +++ b/hugr-passes/src/const_fold.rs @@ -15,7 +15,7 @@ use hugr_core::{ }; use value_handle::ValueHandle; -use crate::composable::{ComposablePass, PassScope, WithScope, validate_if_test}; +use crate::composable::{ComposablePass, PassScope, WithScope}; use crate::dataflow::{ ConstLoader, ConstLocation, DFContext, Machine, PartialValue, TailLoopTermination, partial_from_const, @@ -26,7 +26,7 @@ use crate::dead_code::{DeadCodeElimError, DeadCodeElimPass, PreserveNode}; /// A configuration for the Constant Folding pass. pub struct ConstantFoldPass { allow_increase_termination: bool, - scope: Option, + scope: PassScope, /// Each outer key Node must be either: /// - a `FuncDefn` child of the root, if the root is a module; or /// - the entrypoint, if the entrypoint is not a Module @@ -101,11 +101,7 @@ impl + 'static> ComposablePass for ConstantFoldPass { /// [`ConstFoldError::InvalidEntryPoint`] if an entry-point added by [`Self::with_inputs`] /// was of an invalid [`OpType`] fn run(&self, hugr: &mut H) -> Result<(), ConstFoldError> { - let Some(root) = self - .scope - .as_ref() - .map_or(Some(hugr.entrypoint()), |sc| sc.root(hugr)) - else { + let Some(root) = self.scope.root(hugr) else { return Ok(()); // Scope says do nothing }; let fresh_node = Node::from(portgraph::NodeIndex::new( @@ -130,7 +126,7 @@ impl + 'static> ComposablePass for ConstantFoldPass { .map_err(|op| ConstFoldError::InvalidEntryPoint { node: n, op })?; } - for node in self.scope.iter().flat_map(|sc| sc.preserve_interface(hugr)) { + for node in self.scope.preserve_interface(hugr) { if node == hugr.module_root() || self.inputs.contains_key(&node) { // Cannot prepopulate inputs for module-root; do not `join` with inputs explicitly specified. continue; @@ -182,12 +178,7 @@ impl + 'static> ComposablePass for ConstantFoldPass { hugr.connect(lcst, OutgoingPort::from(0), n, inport); } // Eliminate dead code not required for the same entry points. - let dce = self - .scope - .as_ref() - .map_or(DeadCodeElimPass::::default(), |scope| { - DeadCodeElimPass::::default_with_scope(scope.clone()) - }); + let dce = DeadCodeElimPass::::default_with_scope(self.scope.clone()); dce.with_entry_points(self.inputs.keys().copied()) .set_preserve_callback(if self.allow_increase_termination { Arc::new(|_, _| PreserveNode::CanRemoveIgnoringChildren) @@ -212,31 +203,11 @@ impl + 'static> ComposablePass for ConstantFoldPass { impl WithScope for ConstantFoldPass { fn with_scope(mut self, scope: impl Into) -> Self { - self.scope = Some(scope.into()); + self.scope = scope.into(); self } } -/// Exhaustively apply constant folding to a HUGR. -/// If the Hugr's entrypoint is its [`Module`], assumes all [`FuncDefn`] children are reachable. -/// -/// [`FuncDefn`]: hugr_core::ops::OpType::FuncDefn -/// [`Module`]: hugr_core::ops::OpType::Module -#[deprecated(note = "Use ConstantFoldPass with a PassScope", since = "0.25.7")] -pub fn constant_fold_pass + 'static>(mut h: impl AsMut) { - let h = h.as_mut(); - let c = ConstantFoldPass::default(); - let c = if h.get_optype(h.entrypoint()).is_module() { - let no_inputs: [(IncomingPort, _); 0] = []; - h.children(h.entrypoint()) - .filter(|n| h.get_optype(*n).is_func_defn()) - .fold(c, |c, n| c.with_inputs(n, no_inputs.iter().cloned())) - } else { - c - }; - validate_if_test(c, h).unwrap(); -} - struct ConstFoldContext; impl ConstLoader> for ConstFoldContext { diff --git a/hugr-passes/src/dead_funcs.rs b/hugr-passes/src/dead_funcs.rs index a2fbcdddfc..61a3710913 100644 --- a/hugr-passes/src/dead_funcs.rs +++ b/hugr-passes/src/dead_funcs.rs @@ -8,12 +8,10 @@ use hugr_core::{ module_graph::{ModuleGraph, StaticNode}, ops::{OpTag, OpTrait}, }; -use itertools::Either; use petgraph::visit::{Dfs, Walker}; -use crate::composable::{ - ComposablePass, PassScope, Preserve, ValidatePassError, WithScope, validate_if_test, -}; +use crate::composable::{Preserve, WithScope}; +use crate::{ComposablePass, PassScope}; #[derive(Debug, thiserror::Error)] #[non_exhaustive] @@ -48,76 +46,28 @@ fn reachable_funcs<'a, H: HugrView>( }) } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] /// A configuration for the Dead Function Removal pass. pub struct RemoveDeadFuncsPass { - entry_points: Either, PassScope>, -} - -impl Default for RemoveDeadFuncsPass { - fn default() -> Self { - Self { - entry_points: Either::Left(Vec::new()), - } - } + scope: PassScope, } -impl RemoveDeadFuncsPass { - #[deprecated(note = "Use RemoveDeadFuncsPass::with_scope", since = "0.25.7")] - /// Adds new entry points - these must be [`FuncDefn`] nodes - /// that are children of the [`Module`] at the root of the Hugr. - /// - /// Overrides any [PassScope] set by a call to [Self::with_scope]. - /// - /// [`FuncDefn`]: hugr_core::ops::OpType::FuncDefn - /// [`Module`]: hugr_core::ops::OpType::Module - pub fn with_module_entry_points( - mut self, - entry_points: impl IntoIterator, - ) -> Self { - let v = match self.entry_points { - Either::Left(ref mut v) => v, - Either::Right(_) => { - self.entry_points = Either::Left(Vec::new()); - self.entry_points.as_mut().unwrap_left() - } - }; - v.extend(entry_points); - self - } -} - -impl> ComposablePass for RemoveDeadFuncsPass { +impl ComposablePass for RemoveDeadFuncsPass { type Error = RemoveDeadFuncsError; type Result = (); fn run(&self, hugr: &mut H) -> Result<(), RemoveDeadFuncsError> { let mut entry_points = Vec::new(); - match &self.entry_points { - Either::Left(ep) => { - for &n in ep { - if !hugr.get_optype(n).is_func_defn() { - return Err(RemoveDeadFuncsError::InvalidEntryPoint { node: n }); - } - debug_assert_eq!(hugr.get_parent(n), Some(hugr.module_root())); - entry_points.push(n); - } - if hugr.entrypoint() != hugr.module_root() { - entry_points.push(hugr.entrypoint()) - } - } - Either::Right( - // If the entrypoint is the module root, not allowed to touch anything. - // Otherwise, we must keep the entrypoint (and can touch only inside it). - PassScope::EntrypointFlat | PassScope::EntrypointRecursive - // Optimize whole Hugr but keep all functions - | PassScope::Global(Preserve::All)) => { - return Ok(()); - } - Either::Right(PassScope::Global(Preserve::Entrypoint)) if hugr.entrypoint() != hugr.module_root() => { + match &self.scope { + // If the entrypoint is the module root, not allowed to touch anything. + // Otherwise, we must keep the entrypoint (and can touch only inside it). + PassScope::EntrypointFlat | PassScope::EntrypointRecursive + // Optimize whole Hugr but keep all functions + | PassScope::Global(Preserve::All) => return Ok(()), + PassScope::Global(Preserve::Entrypoint) if hugr.entrypoint() != hugr.module_root() => { entry_points.push(hugr.entrypoint()); } - Either::Right(PassScope::Global(_)) => { + PassScope::Global(_) => { for n in hugr.children(hugr.module_root()) { if hugr.get_optype(n).as_func_defn().is_some_and(|fd| fd.visibility() == &Visibility::Public) { @@ -156,39 +106,13 @@ impl> ComposablePass for RemoveDeadFuncsPass { impl WithScope for RemoveDeadFuncsPass { fn with_scope(mut self, scope: impl Into) -> Self { - self.entry_points = Either::Right(scope.into()); + self.scope = scope.into(); self } } -/// Deletes from the Hugr any functions that are not used by either `Call` or -/// `LoadFunction` nodes in reachable parts. -/// -/// `entry_points` may provide a list of entry points, which must be [`FuncDefn`]s (children of the root). -/// The [HugrView::entrypoint] will also be used unless it is the [HugrView::module_root]. -/// Note that for a [`Module`]-rooted Hugr with no `entry_points` provided, this will remove -/// all functions from the module. -/// -/// # Errors -/// * If any node in `entry_points` is not a [`FuncDefn`] -/// -/// [`FuncDefn`]: hugr_core::ops::OpType::FuncDefn -/// [`Module`]: hugr_core::ops::OpType::Module -#[deprecated(note = "Use RemoveDeadFuncsPass with a PassScope", since = "0.25.7")] -#[expect(deprecated)] -pub fn remove_dead_funcs( - h: &mut impl HugrMut, - entry_points: impl IntoIterator, -) -> Result<(), ValidatePassError> { - validate_if_test( - RemoveDeadFuncsPass::default().with_module_entry_points(entry_points), - h, - ) -} - #[cfg(test)] mod test { - use std::collections::HashMap; use hugr_core::builder::{Dataflow, DataflowSubContainer, HugrBuilder, ModuleBuilder}; use hugr_core::hugr::hugrmut::HugrMut; @@ -240,53 +164,6 @@ mod test { h } - #[rstest] - #[case(false, [], vec![])] // No entry_points removes everything! - #[case(true, [], vec!["from_main", "main"])] - #[case(false, ["main"], vec!["from_main", "main"])] - #[case(false, ["from_main"], vec!["from_main"])] - #[case(false, ["pubfunc"], vec!["from_pub", "pubfunc"])] - #[case(true, ["from_pub"], vec!["from_main", "from_pub", "main"])] - #[case(false, ["from_pub", "pubfunc"], vec!["from_pub", "pubfunc"])] - fn remove_dead_funcs_entry_points( - #[case] use_hugr_entrypoint: bool, - #[case] entry_points: impl IntoIterator, - #[case] retained_funcs: Vec<&'static str>, - ) -> Result<(), Box> { - let mut hugr = hugr(use_hugr_entrypoint); - - let avail_funcs = hugr - .children(hugr.module_root()) - .filter_map(|n| { - hugr.get_optype(n) - .as_func_defn() - .map(|fd| (fd.func_name().clone(), n)) - }) - .collect::>(); - - #[expect(deprecated)] - super::remove_dead_funcs( - &mut hugr, - entry_points - .into_iter() - .map(|name| *avail_funcs.get(name).unwrap()) - .collect::>(), - ) - .unwrap(); - - let remaining_funcs = hugr - .nodes() - .filter_map(|n| { - hugr.get_optype(n) - .as_func_defn() - .map(|fd| fd.func_name().as_str()) - }) - .sorted() - .collect_vec(); - assert_eq!(remaining_funcs, retained_funcs); - Ok(()) - } - #[rstest] #[case(Preserve::All, false, vec!["from_main", "from_pub", "main", "pubfunc"])] #[case(PassScope::EntrypointFlat, true, vec!["from_main", "from_pub", "main", "pubfunc"])] diff --git a/hugr-passes/src/lib.rs b/hugr-passes/src/lib.rs index ceb58539c6..5ae1729db9 100644 --- a/hugr-passes/src/lib.rs +++ b/hugr-passes/src/lib.rs @@ -27,16 +27,10 @@ pub use composable::{ComposablePass, InScope, PassScope}; // Pass re-exports pub use dead_code::DeadCodeElimPass; -#[deprecated(note = "Use RemoveDeadFuncsPass instead", since = "0.25.7")] -#[expect(deprecated)] // Remove together -pub use dead_funcs::remove_dead_funcs; pub use dead_funcs::{RemoveDeadFuncsError, RemoveDeadFuncsPass}; pub use force_order::{force_order, force_order_by_key}; pub use inline_funcs::inline_acyclic; pub use lower::{lower_ops, replace_many_ops}; -#[deprecated(note = "Use MonomorphizePass instead", since = "0.25.7")] -#[expect(deprecated)] // Remove together -pub use monomorphize::monomorphize; pub use monomorphize::{MonomorphizePass, mangle_name}; #[deprecated( note = "Use LocalizeEdgesPass::check_no_nonlocal_edges", diff --git a/hugr-passes/src/monomorphize.rs b/hugr-passes/src/monomorphize.rs index bb572cf024..ac411851e7 100644 --- a/hugr-passes/src/monomorphize.rs +++ b/hugr-passes/src/monomorphize.rs @@ -13,32 +13,9 @@ use hugr_core::{ use hugr_core::hugr::{HugrView, OpType, hugrmut::HugrMut}; use itertools::Itertools as _; -use crate::composable::{ValidatePassError, WithScope, validate_if_test}; +use crate::composable::WithScope; use crate::{ComposablePass, PassScope}; -/// Replaces calls to polymorphic functions with calls to new monomorphic -/// instantiations of the polymorphic ones. -/// -/// If the Hugr is [Module](OpType::Module)-rooted, -/// * then the original polymorphic [`FuncDefn`]s are left untouched (including Calls inside them) -/// - [`crate::remove_dead_funcs`] can be used when no other Hugr will be linked in that might instantiate these -/// * else, the originals are removed (they are invisible from outside the Hugr); however, note -/// that this behaviour is expected to change in a future release to match Module-rooted Hugrs. -/// -/// If the Hugr is [`FuncDefn`](OpType::FuncDefn)-rooted with polymorphic -/// signature then the HUGR will not be modified. -/// -/// Monomorphic copies of polymorphic functions will be added to the HUGR as -/// children of the root node. We make best effort to ensure that names (derived -/// from parent function names and concrete type args) of new functions are unique -/// whenever the names of their parents are unique, but this is not guaranteed. -#[deprecated(note = "Use MonomorphizePass instead", since = "0.25.7")] -pub fn monomorphize( - hugr: &mut impl HugrMut, -) -> Result<(), ValidatePassError> { - validate_if_test(MonomorphizePass::default(), hugr) -} - fn is_polymorphic(fd: &FuncDefn) -> bool { !fd.signature().params().is_empty() } @@ -187,10 +164,10 @@ fn instantiate( /// Replaces calls to polymorphic functions with calls to new monomorphic /// instantiations of the polymorphic ones. /// -/// The original polymorphic [`FuncDefn`]s are left untouched (including Calls inside them). -/// Call [`crate::remove_dead_funcs`] to remove them. +/// The original polymorphic [`FuncDefn`]s are left untouched (including Calls inside +/// them); they can be removed by e.g. [`crate::RemoveDeadFuncsPass`]. /// -/// If the Hugr is [`FuncDefn`](OpType::FuncDefn)-rooted with polymorphic +/// If the Hugr's entrypoint is a [`FuncDefn`](OpType::FuncDefn) with polymorphic /// signature then the HUGR will not be modified. /// /// Monomorphic copies of polymorphic functions will be added to the HUGR as diff --git a/hugr-passes/src/normalize_cfgs.rs b/hugr-passes/src/normalize_cfgs.rs index 8b6b81b266..a051e61e8d 100644 --- a/hugr-passes/src/normalize_cfgs.rs +++ b/hugr-passes/src/normalize_cfgs.rs @@ -97,71 +97,34 @@ pub enum NormalizeCFGResult { } /// A [ComposablePass] that normalizes CFGs (i.e. [normalize_cfg]) in a Hugr. -#[derive(Clone, Debug)] -pub struct NormalizeCFGPass { - scope: Either, PassScope>, +#[derive(Clone, Debug, Default)] +pub struct NormalizeCFGPass { + scope: PassScope, } -impl Default for NormalizeCFGPass { - fn default() -> Self { - Self { - scope: Either::Left(vec![]), - } - } -} - -impl NormalizeCFGPass { - /// Allows mutating the set of CFG nodes that will be normalized. - /// - /// Note that calling this method (even if the returned mut-ref is not written to) will - /// override any previous call to [Self::with_scope]. - /// - /// If empty (the default), all (non-strict) descendants of the [HugrView::entrypoint] - /// will be normalized. - #[deprecated(note = "Use with_scope", since = "0.25.7")] - pub fn cfgs(&mut self) -> &mut Vec { - match &mut self.scope { - Either::Left(cfgs) => cfgs, - r => { - *r = Either::Left(Vec::new()); - r.as_mut().unwrap_left() - } - } - } -} - -impl ComposablePass for NormalizeCFGPass { +impl ComposablePass for NormalizeCFGPass { type Error = NormalizeCFGError; /// For each CFG node that was normalized, the [NormalizeCFGResult] for that CFG type Result = HashMap>; fn run(&self, hugr: &mut H) -> Result { - let cfgs = match &self.scope { - Either::Left(cfgs) if !cfgs.is_empty() => cfgs.clone(), - _ => { - let ctrs = match &self.scope { - Either::Left(v) => { - assert!(v.is_empty()); - Either::Right(hugr.descendants(hugr.entrypoint())) - } - Either::Right(scope) => { - let r = scope.root(hugr); - if let Some(r) = r.filter(|_| scope.recursive()) { - Either::Right(hugr.descendants(r)) - } else { - Either::Left(r.into_iter()) - } - } - }; - let mut cfgs: Vec = - ctrs.filter(|n| hugr.get_optype(*n).is_cfg()).collect(); - // Process inner CFGs first, in case they are removed (if they are in a completely - // disconnected block when the Entry node has only the Exit as successor). - cfgs.reverse(); - cfgs + let ctrs = { + let r = self.scope.root(hugr); + if let Some(r) = r.filter(|_| self.scope.recursive()) { + Either::Right(hugr.descendants(r)) + } else { + Either::Left(r.into_iter()) } }; + + let cfgs = { + let mut cfgs: Vec = ctrs.filter(|n| hugr.get_optype(*n).is_cfg()).collect(); + // Process inner CFGs first, in case they are removed (if they are in a completely + // disconnected block when the Entry node has only the Exit as successor). + cfgs.reverse(); + cfgs + }; let mut results = HashMap::new(); for cfg in cfgs { let res = normalize_cfg(&mut hugr.with_entrypoint_mut(cfg))?; @@ -171,9 +134,9 @@ impl ComposablePass for NormalizeCFGPass { } } -impl WithScope for NormalizeCFGPass { +impl WithScope for NormalizeCFGPass { fn with_scope(mut self, scope: impl Into) -> Self { - self.scope = Either::Right(scope.into()); + self.scope = scope.into(); self } } diff --git a/hugr-passes/src/replace_types.rs b/hugr-passes/src/replace_types.rs index 1f09853779..ced3ac48f7 100644 --- a/hugr-passes/src/replace_types.rs +++ b/hugr-passes/src/replace_types.rs @@ -57,7 +57,7 @@ pub enum NodeTemplate { /// /// It is **recommended** to use [Self::LinkedHugr] instead. /// - /// [monomorphization]: super::monomorphize + /// [monomorphization]: crate::MonomorphizePass CompoundOp(Box), /// Defines a sub-Hugr to insert, whose entrypoint becomes (or replaces) the desired Node. /// Other children of the Hugr reachable from the entrypoint will also be inserted @@ -365,7 +365,7 @@ impl ReplacementOptions { /// would use `SpecialListOfXs`.) /// * See also limitations noted for [Linearizer]. /// -/// [monomorphization]: super::monomorphize() +/// [monomorphization]: crate::MonomorphizePass #[derive(Clone)] pub struct ReplaceTypes { type_map: HashMap, @@ -482,7 +482,7 @@ impl ReplaceTypes { /// /// Note that if `src` is an instance of a *parametrized* [`TypeDef`], this takes /// precedence over [`Self::replace_parametrized_type`] where the `src`s overlap. Thus, this - /// should only be used on already-*[monomorphize](super::monomorphize())d* Hugrs, as + /// should only be used on already-*[monomorphize](crate::MonomorphizePass)d* Hugrs, as /// substitution (parametric polymorphism) happening later will not respect this replacement. /// /// If there are any [`LoadConstant`]s of this type, callers should also call [`Self::replace_consts`] @@ -611,7 +611,7 @@ impl ReplaceTypes { /// /// Note that if `src` is an instance of a *parametrized* [`OpDef`], this takes /// precedence over [`Self::set_replace_parametrized_op`] where the `src`s overlap. - /// Thus, this method should only be used for already-*[monomorphize](super::monomorphize())d* + /// Thus, this method should only be used for already-*[monomorphize](crate::MonomorphizePass)d* /// Hugrs, as substitution (parametric polymorphism) happening later will not respect /// this replacement. pub fn set_replace_op(&mut self, src: &ExtensionOp, dest: NodeTemplate) { diff --git a/hugr-passes/src/replace_types/linearize.rs b/hugr-passes/src/replace_types/linearize.rs index 2d646567b1..4bff5f3fc4 100644 --- a/hugr-passes/src/replace_types/linearize.rs +++ b/hugr-passes/src/replace_types/linearize.rs @@ -28,7 +28,7 @@ use super::{NodeTemplate, ParametricType}; /// would be a specific instantiation of the function for the /// type-that-becomes-linear, into which copy/discard can be inserted. /// -/// [monomorphization]: crate::monomorphize() +/// [monomorphization]: crate::MonomorphizePass /// [Copyable]: hugr_core::types::TypeBound::Copyable pub trait Linearizer { /// Insert copy or discard operations (as appropriate) enough to wire `src` diff --git a/hugr-passes/src/untuple.rs b/hugr-passes/src/untuple.rs index 93722b0138..7c8a440aac 100644 --- a/hugr-passes/src/untuple.rs +++ b/hugr-passes/src/untuple.rs @@ -11,31 +11,11 @@ use hugr_core::hugr::views::sibling_subgraph::TopoConvexChecker; use hugr_core::ops::{OpTrait, OpType}; use hugr_core::types::Type; use hugr_core::{HugrView, Node, PortIndex, SimpleReplacement}; -use itertools::{Either, Itertools}; +use itertools::Itertools; use crate::composable::WithScope; use crate::{ComposablePass, PassScope}; -/// Configuration enum for the untuple rewrite pass. -/// -/// Indicates whether the pattern match should traverse the HUGR recursively. -#[deprecated(note = "Use PassScope instead", since = "0.25.7")] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum UntupleRecursive { - /// Traverse the HUGR recursively, i.e. consider the entire subtree - Recursive, - /// Do not traverse the HUGR recursively, i.e. consider only the sibling subgraph - NonRecursive, -} - -#[expect(deprecated)] // Remove along with UntupleRecursive -#[expect(clippy::derivable_impls)] // derive(Default) generates deprecation warning -impl Default for UntupleRecursive { - fn default() -> Self { - UntupleRecursive::NonRecursive - } -} - /// A pass that removes unnecessary `MakeTuple` operations immediately followed /// by `UnpackTuple`s. /// @@ -51,29 +31,9 @@ impl Default for UntupleRecursive { /// /// Ignores pack/unpack nodes with order edges. // TODO: Supporting those requires updating the `SiblingSubgraph` implementation. See . -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct UntuplePass { - /// Either a [PassScope] controlling which parts of the Hugr to process; - /// or a flag for recursiveness, and the parent node under which to operate - /// (None indicating the Hugr root) - #[expect(deprecated)] // remove Right half and just use PassScope - scope: Either)>, -} - -impl Default for UntuplePass { - fn default() -> Self { - #[expect(deprecated)] // Move to PassScope::Default() when UntupleRecursive is removed - Self { - scope: Either::Right((UntupleRecursive::default(), Option::default())), - } - } -} - -#[expect(deprecated)] // Remove along with UntupleRecursive -impl From for bool { - fn from(value: UntupleRecursive) -> Self { - value == UntupleRecursive::Recursive - } + scope: PassScope, } #[derive(Debug, derive_more::Display, derive_more::Error, derive_more::From)] @@ -92,75 +52,6 @@ pub struct UntupleResult { } impl UntuplePass { - /// Create a new untuple pass with the given recursiveness and that - /// will run on the entrypoint region/subtree. - #[must_use] - #[deprecated( - note = "Use default() instead, followed by with_scope()", - since = "0.25.7" - )] - #[expect(deprecated)] // Remove along with UntupleRecursive - pub fn new(recursive: UntupleRecursive) -> Self { - Self { - scope: Either::Right((recursive, None)), - } - } - - /// Sets the parent node to optimize (overwrites any previous setting) - /// - /// If the pass was previously configured by [Self::with_scope] then - /// implicitly `[Self::set_recursive]`'s with [PassScope::recursive] - #[deprecated(note = "Use with_scope instead", since = "0.25.7")] - #[expect(deprecated)] // Remove along with UntupleRecursive - pub fn set_parent(mut self, parent: impl Into>) -> Self { - match &mut self.scope { - Either::Left(p) => { - let rec = if p.recursive() { - UntupleRecursive::Recursive - } else { - UntupleRecursive::NonRecursive - }; - self.scope = Either::Right((rec, parent.into())) - } - Either::Right((_, p)) => *p = parent.into(), - }; - self - } - - /// Sets whether the pass should traverse the HUGR recursively. - /// - /// If the pass was last configured via [Self::with_scope], overrides that, - /// with `set_parent` of default `None`. - #[must_use] - #[deprecated(note = "Use with_scope", since = "0.25.7")] - #[expect(deprecated)] // Remove along with UntupleRecursive - pub fn recursive(mut self, recursive: UntupleRecursive) -> Self { - let parent = self.scope.right().and_then(|(_, p)| p); - self.scope = Either::Right((recursive, parent)); - self - } - - /// Find tuple pack operations followed by tuple unpack operations - /// beneath a specified parent and according to this instance's recursiveness - /// ([Self::recursive] or [Self::with_scope] + [PassScope::recursive]) - /// and generate rewrites to remove them. - /// - /// The returned rewrites are guaranteed to be independent of each other. - /// - /// Returns an iterator over the rewrites. - #[deprecated(note = "Use all_rewrites", since = "0.25.7")] - pub fn find_rewrites( - &self, - hugr: &H, - parent: H::Node, - ) -> Vec> { - let recursive = match &self.scope { - Either::Left(scope) => scope.recursive(), - Either::Right((rec, _)) => (*rec).into(), - }; - find_rewrites(hugr, parent, recursive) - } - /// Find tuple pack operations followed by tuple unpack operations /// and generate rewrites to remove them. /// @@ -171,16 +62,10 @@ impl UntuplePass { &self, hugr: &H, ) -> Vec> { - let (recursive, parent) = match &self.scope { - Either::Left(scope) => { - let Some(root) = scope.root(hugr) else { - return vec![]; - }; - (scope.recursive(), root) - } - Either::Right((rec, parent)) => ((*rec).into(), parent.unwrap_or(hugr.entrypoint())), + let Some(parent) = self.scope.root(hugr) else { + return vec![]; }; - find_rewrites(hugr, parent, recursive) + find_rewrites(hugr, parent, self.scope.recursive()) } } @@ -226,9 +111,8 @@ impl> ComposablePass for UntuplePass { } impl WithScope for UntuplePass { - /// Overrides any [Self::set_parent] or [Self::recursive] fn with_scope(mut self, scope: impl Into) -> Self { - self.scope = Either::Left(scope.into()); + self.scope = scope.into(); self } } @@ -572,15 +456,9 @@ mod test { #[case] mut hugr: Hugr, #[case] expected_rewrites: usize, #[case] remaining_nodes: usize, - #[values(true, false)] use_scope: bool, ) { let parent = hugr.entrypoint(); - let pass = if use_scope { - UntuplePass::default().with_scope(PassScope::EntrypointFlat) - } else { - #[expect(deprecated)] // Remove use_scope==false case along with UntupleRecursive - UntuplePass::default().set_parent(parent) - }; + let pass = UntuplePass::default().with_scope(PassScope::EntrypointFlat); let res = pass.run(&mut hugr).unwrap_or_else(|e| panic!("{e}")); assert_eq!(res.rewrites_applied, expected_rewrites); assert_eq!(hugr.children(parent).count(), remaining_nodes);