Skip to content

Commit e610678

Browse files
authored
feat!: Remove RootCheckable (#2704)
Closes #2577 . BREAKING CHANGE: Use `RootChecked` or `HugrView` instead of `RootCheckable`.
1 parent ecc8bf0 commit e610678

File tree

8 files changed

+54
-70
lines changed

8 files changed

+54
-70
lines changed

hugr-core/src/hugr/views.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub use self::petgraph::PetgraphWrapper;
1919
use self::render::{MermaidFormatter, RenderConfig};
2020
pub use nodes_iter::NodesIter;
2121
pub use rerooted::Rerooted;
22-
pub use root_checked::{InvalidSignature, RootCheckable, RootChecked, check_tag};
22+
pub use root_checked::{InvalidSignature, RootChecked, check_tag};
2323
pub use sibling_subgraph::SiblingSubgraph;
2424

2525
use itertools::Itertools;

hugr-core/src/hugr/views/root_checked.rs

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -67,26 +67,6 @@ impl<H: AsRef<Hugr>, Handle> AsRef<Hugr> for RootChecked<H, Handle> {
6767
}
6868
}
6969

70-
/// A trait for types that can be checked for a specific [`OpTag`] at their entrypoint node.
71-
///
72-
/// This is used mainly specifying function inputs that may either be a [`HugrView`] or an already checked [`RootChecked`].
73-
pub trait RootCheckable<H: HugrView, Handle: NodeHandle<H::Node>>: Sized {
74-
/// Wrap the Hugr in a [`RootChecked`] if it is valid for the required [`OpTag`].
75-
///
76-
/// If `Self` is already a [`RootChecked`], it is a no-op.
77-
fn try_into_checked(self) -> Result<RootChecked<H, Handle>, HugrError>;
78-
}
79-
impl<H: HugrView, Handle: NodeHandle<H::Node>> RootCheckable<H, Handle> for H {
80-
fn try_into_checked(self) -> Result<RootChecked<H, Handle>, HugrError> {
81-
RootChecked::try_new(self)
82-
}
83-
}
84-
impl<H: HugrView, Handle: NodeHandle<H::Node>> RootCheckable<H, Handle> for RootChecked<H, Handle> {
85-
fn try_into_checked(self) -> Result<RootChecked<H, Handle>, HugrError> {
86-
Ok(self)
87-
}
88-
}
89-
9070
/// Check that the node in a HUGR can be represented by the required tag.
9171
pub fn check_tag<Required: NodeHandle<N>, N>(
9272
hugr: &impl HugrView<Node = N>,

hugr-core/src/hugr/views/sibling_subgraph.rs

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use crate::ops::{NamedOp, OpTag, OpTrait, OpType};
2727
use crate::types::{Signature, Type};
2828
use crate::{Hugr, IncomingPort, Node, OutgoingPort, Port, SimpleReplacement};
2929

30-
use super::root_checked::RootCheckable;
30+
use super::RootChecked;
3131

3232
/// A non-empty convex subgraph of a HUGR sibling graph.
3333
///
@@ -110,15 +110,12 @@ impl<N: HugrNode> SiblingSubgraph<N> {
110110
/// This will return an [`InvalidSubgraph::EmptySubgraph`] error if the
111111
/// subgraph is empty.
112112
pub fn try_new_dataflow_subgraph<'h, H, Root>(
113-
dfg_graph: impl RootCheckable<&'h H, Root>,
113+
dfg_graph: RootChecked<&'h H, Root>,
114114
) -> Result<Self, InvalidSubgraph<N>>
115115
where
116116
H: 'h + Clone + HugrView<Node = N>,
117117
Root: ContainerHandle<N, ChildrenHandle = DataflowOpID>,
118118
{
119-
let Ok(dfg_graph) = dfg_graph.try_into_checked() else {
120-
return Err(InvalidSubgraph::NonDataflowRegion);
121-
};
122119
let dfg_graph = dfg_graph.into_hugr();
123120

124121
let parent = HugrView::entrypoint(&dfg_graph);
@@ -1651,7 +1648,9 @@ mod tests {
16511648
fn construct_simple_replacement() -> Result<(), InvalidSubgraph> {
16521649
let (mut hugr, func_root) = build_hugr().unwrap();
16531650
let func = hugr.with_entrypoint(func_root);
1654-
let sub = SiblingSubgraph::try_new_dataflow_subgraph::<_, FuncID<true>>(&func)?;
1651+
let sub = SiblingSubgraph::try_new_dataflow_subgraph::<_, FuncID<true>>(
1652+
RootChecked::try_new(&func).expect("Root should be FuncDefn."),
1653+
)?;
16551654
assert!(sub.validate(&func, Default::default()).is_ok());
16561655

16571656
let empty_dfg = {
@@ -1699,7 +1698,9 @@ mod tests {
16991698
fn test_signature() -> Result<(), InvalidSubgraph> {
17001699
let (hugr, dfg) = build_hugr().unwrap();
17011700
let func = hugr.with_entrypoint(dfg);
1702-
let sub = SiblingSubgraph::try_new_dataflow_subgraph::<_, FuncID<true>>(&func)?;
1701+
let sub = SiblingSubgraph::try_new_dataflow_subgraph::<_, FuncID<true>>(
1702+
RootChecked::try_new(&func).expect("Root should be FuncDefn."),
1703+
)?;
17031704
assert!(sub.validate(&func, Default::default()).is_ok());
17041705
assert_eq!(
17051706
sub.signature(&func),
@@ -1732,10 +1733,12 @@ mod tests {
17321733
let (hugr, func_root) = build_hugr().unwrap();
17331734
let func = hugr.with_entrypoint(func_root);
17341735
assert_eq!(
1735-
SiblingSubgraph::try_new_dataflow_subgraph::<_, FuncID<true>>(&func)
1736-
.unwrap()
1737-
.nodes()
1738-
.len(),
1736+
SiblingSubgraph::try_new_dataflow_subgraph::<_, FuncID<true>>(
1737+
RootChecked::try_new(&func).expect("Root should be FuncDefn.")
1738+
)
1739+
.unwrap()
1740+
.nodes()
1741+
.len(),
17391742
4
17401743
);
17411744
}
@@ -1848,8 +1851,10 @@ mod tests {
18481851
fn preserve_signature() {
18491852
let (hugr, func_root) = build_hugr_classical().unwrap();
18501853
let func_graph = hugr.with_entrypoint(func_root);
1851-
let func =
1852-
SiblingSubgraph::try_new_dataflow_subgraph::<_, FuncID<true>>(&func_graph).unwrap();
1854+
let func = SiblingSubgraph::try_new_dataflow_subgraph::<_, FuncID<true>>(
1855+
RootChecked::try_new(&func_graph).expect("Root should be FuncDefn."),
1856+
)
1857+
.unwrap();
18531858
let func_defn = hugr.get_optype(func_root).as_func_defn().unwrap();
18541859
assert_eq!(func_defn.signature(), &func.signature(&func_graph).into());
18551860
}
@@ -1858,8 +1863,10 @@ mod tests {
18581863
fn extract_subgraph() {
18591864
let (hugr, func_root) = build_hugr().unwrap();
18601865
let func_graph = hugr.with_entrypoint(func_root);
1861-
let subgraph =
1862-
SiblingSubgraph::try_new_dataflow_subgraph::<_, FuncID<true>>(&func_graph).unwrap();
1866+
let subgraph = SiblingSubgraph::try_new_dataflow_subgraph::<_, FuncID<true>>(
1867+
RootChecked::try_new(&func_graph).expect("Root should be FuncDefn."),
1868+
)
1869+
.unwrap();
18631870
let extracted = subgraph.extract_subgraph(&hugr, "region");
18641871

18651872
extracted.validate().unwrap();
@@ -1883,7 +1890,10 @@ mod tests {
18831890
.outputs();
18841891
let outw = [outw1].into_iter().chain(outw2);
18851892
let h = builder.finish_hugr_with_outputs(outw).unwrap();
1886-
let subg = SiblingSubgraph::try_new_dataflow_subgraph::<_, DfgID>(&h).unwrap();
1893+
let subg = SiblingSubgraph::try_new_dataflow_subgraph::<_, DfgID>(
1894+
RootChecked::try_new(&h).expect("Root should be DFG."),
1895+
)
1896+
.unwrap();
18871897
assert_eq!(subg.nodes().len(), 2);
18881898
}
18891899

@@ -2178,9 +2188,10 @@ mod tests {
21782188

21792189
#[rstest]
21802190
fn test_call_subgraph_from_dfg(hugr_call_subgraph: Hugr) {
2181-
let subg =
2182-
SiblingSubgraph::try_new_dataflow_subgraph::<_, DataflowParentID>(&hugr_call_subgraph)
2183-
.unwrap();
2191+
let subg = SiblingSubgraph::try_new_dataflow_subgraph::<_, DataflowParentID>(
2192+
RootChecked::try_new(&hugr_call_subgraph).expect("Root should be DFG container."),
2193+
)
2194+
.unwrap();
21842195

21852196
assert_eq!(subg.function_calls.len(), 1);
21862197
assert_eq!(subg.function_calls[0].len(), 2);

hugr-passes/src/half_node.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::hash::Hash;
33
use super::nest_cfgs::CfgNodeMap;
44

55
use hugr_core::hugr::internal::HugrInternals;
6-
use hugr_core::hugr::views::RootCheckable;
6+
use hugr_core::hugr::views::RootChecked;
77
use hugr_core::ops::handle::CfgID;
88
use hugr_core::ops::{OpTag, OpTrait};
99
use hugr_core::{Direction, HugrView, Node};
@@ -32,9 +32,8 @@ struct HalfNodeView<H: HugrInternals> {
3232

3333
impl<H: HugrView> HalfNodeView<H> {
3434
#[allow(unused)]
35-
pub(crate) fn new(h: impl RootCheckable<H, CfgID<H::Node>>) -> Self {
36-
let checked = h.try_into_checked().expect("Hugr must be a CFG region");
37-
let h = checked.into_hugr();
35+
pub(crate) fn new(h: RootChecked<H, CfgID<H::Node>>) -> Self {
36+
let h = h.into_hugr();
3837

3938
let (entry, exit) = {
4039
let mut children = h.children(h.entrypoint());
@@ -99,6 +98,7 @@ mod test {
9998
use super::super::nest_cfgs::{EdgeClassifier, test::*};
10099
use super::{HalfNode, HalfNodeView};
101100
use hugr_core::builder::BuildError;
101+
use hugr_core::hugr::views::RootChecked;
102102
use hugr_core::ops::handle::NodeHandle;
103103

104104
use itertools::Itertools;
@@ -118,7 +118,7 @@ mod test {
118118
// \---<---<---<---<---<---<---<---<---<---/
119119
// Allowing to identify two nested regions (and fixing the problem with an IdentityCfgMap on the same example)
120120

121-
let v = HalfNodeView::new(&h);
121+
let v = HalfNodeView::new(RootChecked::try_new(&h).expect("Root should be CFG."));
122122

123123
let edge_classes = EdgeClassifier::get_edge_classes(&v);
124124
let HalfNodeView { h: _, entry, exit } = v;

hugr-passes/src/lib.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub mod untuple;
2525
/// Merge basic blocks. Subset of [normalize_cfgs], use the latter.
2626
#[deprecated(note = "Use normalize_cfgs", since = "0.23.0")]
2727
pub mod merge_bbs {
28-
use hugr_core::hugr::{hugrmut::HugrMut, views::RootCheckable};
28+
use hugr_core::hugr::{hugrmut::HugrMut, views::RootChecked};
2929
use hugr_core::ops::handle::CfgID;
3030

3131
/// Merge any basic blocks that are direct children of the specified CFG
@@ -38,11 +38,8 @@ pub mod merge_bbs {
3838
///
3939
/// [OpType::CFG]: hugr_core::ops::OpType::CFG
4040
#[deprecated(note = "Use version in normalize_cfgs", since = "0.23.0")]
41-
pub fn merge_basic_blocks<'h, H: 'h + HugrMut>(
42-
cfg: impl RootCheckable<&'h mut H, CfgID<H::Node>>,
43-
) {
44-
let checked = cfg.try_into_checked().expect("Hugr must be a CFG region");
45-
super::normalize_cfgs::merge_basic_blocks(checked.into_hugr()).unwrap();
41+
pub fn merge_basic_blocks<'h, H: 'h + HugrMut>(cfg: RootChecked<&'h mut H, CfgID<H::Node>>) {
42+
super::normalize_cfgs::merge_basic_blocks(cfg.into_hugr()).unwrap();
4643
}
4744
}
4845

hugr-passes/src/nest_cfgs.rs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,10 @@ use itertools::Itertools;
4545
use thiserror::Error;
4646

4747
use hugr_core::hugr::patch::outline_cfg::OutlineCfg;
48-
use hugr_core::hugr::views::{HugrView, RootCheckable};
48+
use hugr_core::hugr::views::HugrView;
4949
use hugr_core::hugr::{Patch, hugrmut::HugrMut};
5050
use hugr_core::ops::OpTag;
5151
use hugr_core::ops::OpTrait;
52-
use hugr_core::ops::handle::CfgID;
5352
use hugr_core::{Direction, Hugr, Node};
5453

5554
/// A "view" of a CFG in a Hugr which allows basic blocks in the underlying CFG to be split into
@@ -220,10 +219,7 @@ pub struct IdentityCfgMap<H: HugrView> {
220219
}
221220
impl<H: HugrView> IdentityCfgMap<H> {
222221
/// Creates an [`IdentityCfgMap`] for the specified CFG
223-
pub fn new(h: impl RootCheckable<H, CfgID<H::Node>>) -> Self {
224-
let h = h.try_into_checked().expect("Hugr must be a CFG region");
225-
let h = h.into_hugr();
226-
222+
pub fn new(h: H) -> Self {
227223
// Panic if malformed enough not to have two children
228224
let (entry, exit) = h.children(h.entrypoint()).take(2).collect_tuple().unwrap();
229225
debug_assert_eq!(h.get_optype(exit).tag(), OpTag::BasicBlockExit);
@@ -582,7 +578,6 @@ pub(crate) mod test {
582578

583579
use hugr_core::Node;
584580
use hugr_core::hugr::patch::insert_identity::{IdentityInsertion, IdentityInsertionError};
585-
use hugr_core::hugr::views::RootChecked;
586581
use hugr_core::ops::Value;
587582
use hugr_core::ops::handle::{BasicBlockID, ConstID, NodeHandle};
588583
use hugr_core::types::{EdgeKind, Signature};
@@ -632,11 +627,11 @@ pub(crate) mod test {
632627
let exit = cfg_builder.exit_block();
633628
cfg_builder.branch(&tail, 0, &exit)?;
634629

635-
let mut h = cfg_builder.finish_hugr()?;
636-
let rc = RootChecked::<_, CfgID>::try_new(&mut h).unwrap();
630+
let h = cfg_builder.finish_hugr()?;
637631
let (entry, exit) = (entry.node(), exit.node());
638632
let (split, merge, head, tail) = (split.node(), merge.node(), head.node(), tail.node());
639-
let edge_classes = EdgeClassifier::get_edge_classes(&IdentityCfgMap::new(rc.as_ref()));
633+
let mut v = IdentityCfgMap::new(h);
634+
let edge_classes = EdgeClassifier::get_edge_classes(&v);
640635
let [&left, &right] = edge_classes
641636
.keys()
642637
.filter(|(s, _)| *s == split)
@@ -657,7 +652,8 @@ pub(crate) mod test {
657652
sorted([(entry, split), (merge, head), (tail, exit)]), // Two regions, conditional and then loop.
658653
])
659654
);
660-
transform_cfg_to_nested(&mut IdentityCfgMap::new(rc));
655+
transform_cfg_to_nested(&mut v);
656+
let h = v.h;
661657
h.validate().unwrap();
662658
assert_eq!(3, depth(&h, entry));
663659
assert_eq!(3, depth(&h, exit));
@@ -693,7 +689,7 @@ pub(crate) mod test {
693689
.try_into()
694690
.unwrap();
695691

696-
let v = IdentityCfgMap::new(RootChecked::try_new(&h).unwrap());
692+
let v = IdentityCfgMap::new(h);
697693
let edge_classes = EdgeClassifier::get_edge_classes(&v);
698694
let [&left, &right] = edge_classes
699695
.keys()
@@ -783,7 +779,7 @@ pub(crate) mod test {
783779
// Here we would like an indication that we can make two nested regions,
784780
// but there is no edge to act as entry to a region containing just the conditional :-(.
785781

786-
let v = IdentityCfgMap::new(RootChecked::try_new(&h).unwrap());
782+
let v = IdentityCfgMap::new(h);
787783
let edge_classes = EdgeClassifier::get_edge_classes(&v);
788784
let IdentityCfgMap { h: _, entry, exit } = v;
789785
// merge is unique predecessor of tail

hugr-persistent/src/walker.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ use hugr_core::ops::handle::DataflowParentID;
6262
use itertools::{Either, Itertools};
6363
use thiserror::Error;
6464

65-
use hugr_core::{Direction, Hugr, HugrView, Port, PortIndex, hugr::views::RootCheckable};
65+
use hugr_core::{Direction, Hugr, HugrView, Port, PortIndex, hugr::views::RootChecked};
6666

6767
use crate::{Commit, PersistentReplacement, PinnedSubgraph};
6868

@@ -302,7 +302,7 @@ impl<'a> Walker<'a> {
302302
pub fn try_create_commit(
303303
&self,
304304
subgraph: impl Into<PinnedSubgraph>,
305-
repl: impl RootCheckable<Hugr, DataflowParentID>,
305+
mut repl: RootChecked<Hugr, DataflowParentID>,
306306
map_boundary: impl Fn(PatchNode, Port) -> Port,
307307
) -> Result<Commit<'a>, InvalidCommit> {
308308
let pinned_subgraph = subgraph.into();
@@ -312,7 +312,6 @@ impl<'a> Walker<'a> {
312312
.map(|id| self.selected_commits.get_commit(id).clone());
313313

314314
let repl = {
315-
let mut repl = repl.try_into_checked().expect("replacement is not DFG");
316315
let new_inputs = subgraph
317316
.incoming_ports()
318317
.iter()
@@ -783,7 +782,7 @@ mod tests {
783782
let commit = walker
784783
.try_create_commit(
785784
PinnedSubgraph::try_from_pinned(std::iter::empty(), [wire], &walker).unwrap(),
786-
empty_hugr,
785+
RootChecked::try_new(empty_hugr).expect("Root should be DFG."),
787786
|node, port| {
788787
assert_eq!(port.index(), 0);
789788
assert!([not0, not2].contains(&node));

hugr-persistent/tests/persistent_walker_example.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use hugr_core::{
88
Hugr, HugrView, IncomingPort, OutgoingPort, Port, PortIndex,
99
builder::{DFGBuilder, Dataflow, DataflowHugr, endo_sig},
1010
extension::prelude::qb_t,
11+
hugr::views::RootChecked,
1112
ops::OpType,
1213
types::EdgeKind,
1314
};
@@ -251,7 +252,7 @@ fn create_commit<'a>(wire: PersistentWire, walker: &Walker<'a>) -> Option<Commit
251252
// Create the commit
252253
walker.try_create_commit(
253254
PinnedSubgraph::try_from_wires(wires, walker).unwrap(),
254-
empty_2qb_hugr(add_swap),
255+
RootChecked::try_new(empty_2qb_hugr(add_swap)).expect("Root should be DFG."),
255256
|_, port| {
256257
// the incoming/outgoing ports of the subgraph map trivially to the empty 2qb
257258
// HUGR
@@ -273,7 +274,7 @@ fn create_commit<'a>(wire: PersistentWire, walker: &Walker<'a>) -> Option<Commit
273274

274275
walker.try_create_commit(
275276
PinnedSubgraph::try_from_wires([wire], walker).unwrap(),
276-
repl_hugr,
277+
RootChecked::try_new(repl_hugr).expect("Root should be DFG."),
277278
|node, port| {
278279
// map the incoming/outgoing ports of the subgraph to the replacement as
279280
// follows:

0 commit comments

Comments
 (0)