1use std::collections::{BTreeMap, HashMap, VecDeque};
4use std::sync::Arc;
5
6use portgraph::{LinkMut, PortMut, PortView, SecondaryMap};
7
8use crate::core::HugrNode;
9use crate::extension::ExtensionRegistry;
10use crate::hugr::views::SiblingSubgraph;
11use crate::hugr::{HugrView, Node, OpType};
12use crate::hugr::{NodeMetadata, Patch};
13use crate::ops::OpTrait;
14use crate::types::Substitution;
15use crate::{Extension, Hugr, IncomingPort, OutgoingPort, Port, PortIndex};
16
17use super::internal::HugrMutInternals;
18use super::views::{
19 Rerooted, panic_invalid_node, panic_invalid_non_entrypoint, panic_invalid_port,
20};
21
22pub trait HugrMut: HugrMutInternals {
24 fn set_entrypoint(&mut self, root: Self::Node);
40
41 fn with_entrypoint_mut(&mut self, entrypoint: Self::Node) -> Rerooted<&mut Self>
52 where
53 Self: Sized,
54 {
55 Rerooted::new(self, entrypoint)
56 }
57
58 fn get_metadata_mut(&mut self, node: Self::Node, key: impl AsRef<str>) -> &mut NodeMetadata;
64
65 fn set_metadata(
71 &mut self,
72 node: Self::Node,
73 key: impl AsRef<str>,
74 metadata: impl Into<NodeMetadata>,
75 );
76
77 fn remove_metadata(&mut self, node: Self::Node, key: impl AsRef<str>);
83
84 fn add_node_with_parent(&mut self, parent: Self::Node, op: impl Into<OpType>) -> Self::Node;
92
93 fn add_node_before(&mut self, sibling: Self::Node, nodetype: impl Into<OpType>) -> Self::Node;
101
102 fn add_node_after(&mut self, sibling: Self::Node, op: impl Into<OpType>) -> Self::Node;
110
111 fn remove_node(&mut self, node: Self::Node) -> OpType;
119
120 fn remove_subtree(&mut self, node: Self::Node);
126
127 fn copy_descendants(
140 &mut self,
141 root: Self::Node,
142 new_parent: Self::Node,
143 subst: Option<Substitution>,
144 ) -> BTreeMap<Self::Node, Self::Node>;
145
146 fn connect(
152 &mut self,
153 src: Self::Node,
154 src_port: impl Into<OutgoingPort>,
155 dst: Self::Node,
156 dst_port: impl Into<IncomingPort>,
157 );
158
159 fn disconnect(&mut self, node: Self::Node, port: impl Into<Port>);
167
168 fn add_other_edge(&mut self, src: Self::Node, dst: Self::Node) -> (OutgoingPort, IncomingPort);
180
181 fn insert_hugr(&mut self, root: Self::Node, other: Hugr) -> InsertionResult<Node, Self::Node> {
192 let region = other.entrypoint();
193 Self::insert_region(self, root, other, region)
194 }
195
196 fn insert_region(
208 &mut self,
209 root: Self::Node,
210 other: Hugr,
211 region: Node,
212 ) -> InsertionResult<Node, Self::Node> {
213 let node_map = self
214 .insert_forest(other, [(region, root)])
215 .expect("No errors possible for single subtree")
216 .node_map;
217 InsertionResult {
218 inserted_entrypoint: node_map[®ion],
219 node_map,
220 }
221 }
222
223 fn insert_from_view<H: HugrView>(
234 &mut self,
235 root: Self::Node,
236 other: &H,
237 ) -> InsertionResult<H::Node, Self::Node> {
238 let ep = other.entrypoint();
239 let node_map = self
240 .insert_view_forest(other, other.descendants(ep), [(ep, root)])
241 .expect("No errors possible for single subtree")
242 .node_map;
243 InsertionResult {
244 inserted_entrypoint: node_map[&ep],
245 node_map,
246 }
247 }
248
249 fn insert_subgraph<H: HugrView>(
264 &mut self,
265 root: Self::Node,
266 other: &H,
267 subgraph: &SiblingSubgraph<H::Node>,
268 ) -> HashMap<H::Node, Self::Node> {
269 self.insert_view_forest(
270 other,
271 subgraph.nodes().iter().cloned(),
272 subgraph.nodes().iter().map(|n| (*n, root)),
273 )
274 .expect("SiblingSubgraph nodes are a set")
275 .node_map
276 }
277
278 fn insert_forest(
296 &mut self,
297 other: Hugr,
298 root_parents: impl IntoIterator<Item = (Node, Self::Node)>,
299 ) -> InsertForestResult<Node, Self::Node>;
300
301 fn insert_view_forest<H: HugrView>(
321 &mut self,
322 other: &H,
323 nodes: impl Iterator<Item = H::Node> + Clone,
324 root_parents: impl IntoIterator<Item = (H::Node, Self::Node)>,
325 ) -> InsertForestResult<H::Node, Self::Node>;
326
327 fn apply_patch<R, E>(&mut self, rw: impl Patch<Self, Outcome = R, Error = E>) -> Result<R, E>
329 where
330 Self: Sized,
331 {
332 rw.apply(self)
333 }
334
335 fn use_extension(&mut self, extension: impl Into<Arc<Extension>>);
342
343 fn use_extensions<Reg>(&mut self, registry: impl IntoIterator<Item = Reg>)
353 where
354 ExtensionRegistry: Extend<Reg>;
355}
356
357pub type InsertForestResult<SN, TN> = Result<InsertedForest<SN, TN>, InsertForestError<SN>>;
363
364#[derive(Clone, Debug, derive_more::Display, derive_more::Error, PartialEq)]
368#[non_exhaustive]
369pub enum InsertForestError<SN: HugrNode = Node> {
370 #[display("Node {_0} would be copied twice")]
372 DuplicateNode(SN),
373 #[display(
376 "Subtree rooted at {subtree} is already being copied as part of that rooted at {parent}"
377 )]
378 SubtreeAlreadyCopied {
379 subtree: SN,
381 parent: SN,
383 },
384}
385
386pub struct InsertionResult<SourceN = Node, TargetN = Node> {
392 pub inserted_entrypoint: TargetN,
398 pub node_map: HashMap<SourceN, TargetN>,
401}
402
403#[derive(Clone, Debug, Default)]
409pub struct InsertedForest<SourceN = Node, TargetN = Node> {
410 pub node_map: HashMap<SourceN, TargetN>,
413}
414
415fn translate_indices<N: HugrNode>(
421 mut source_node: impl FnMut(portgraph::NodeIndex) -> N,
422 mut target_node: impl FnMut(portgraph::NodeIndex) -> Node,
423 node_map: HashMap<portgraph::NodeIndex, portgraph::NodeIndex>,
424) -> impl Iterator<Item = (N, Node)> {
425 node_map
426 .into_iter()
427 .map(move |(k, v)| (source_node(k), target_node(v)))
428}
429
430impl HugrMut for Hugr {
432 #[inline]
433 fn set_entrypoint(&mut self, root: Node) {
434 panic_invalid_node(self, root);
435 self.entrypoint = root.into_portgraph();
436 }
437
438 fn get_metadata_mut(&mut self, node: Self::Node, key: impl AsRef<str>) -> &mut NodeMetadata {
439 panic_invalid_node(self, node);
440 self.node_metadata_map_mut(node)
441 .entry(key.as_ref())
442 .or_insert(serde_json::Value::Null)
443 }
444
445 fn set_metadata(
446 &mut self,
447 node: Self::Node,
448 key: impl AsRef<str>,
449 metadata: impl Into<NodeMetadata>,
450 ) {
451 let entry = self.get_metadata_mut(node, key);
452 *entry = metadata.into();
453 }
454
455 fn remove_metadata(&mut self, node: Self::Node, key: impl AsRef<str>) {
456 panic_invalid_node(self, node);
457 let node_meta = self.node_metadata_map_mut(node);
458 node_meta.remove(key.as_ref());
459 }
460
461 fn add_node_with_parent(&mut self, parent: Node, node: impl Into<OpType>) -> Node {
462 let node = self.as_mut().add_node(node.into());
463 self.hierarchy
464 .push_child(node.into_portgraph(), parent.into_portgraph())
465 .expect("Inserting a newly-created node into the hierarchy should never fail.");
466 node
467 }
468
469 fn add_node_before(&mut self, sibling: Node, nodetype: impl Into<OpType>) -> Node {
470 let node = self.as_mut().add_node(nodetype.into());
471 self.hierarchy
472 .insert_before(node.into_portgraph(), sibling.into_portgraph())
473 .expect("Inserting a newly-created node into the hierarchy should never fail.");
474 node
475 }
476
477 fn add_node_after(&mut self, sibling: Node, op: impl Into<OpType>) -> Node {
478 let node = self.as_mut().add_node(op.into());
479 self.hierarchy
480 .insert_after(node.into_portgraph(), sibling.into_portgraph())
481 .expect("Inserting a newly-created node into the hierarchy should never fail.");
482 node
483 }
484
485 fn remove_node(&mut self, node: Node) -> OpType {
486 panic_invalid_non_entrypoint(self, node);
487 self.hierarchy.remove(node.into_portgraph());
488 self.graph.remove_node(node.into_portgraph());
489 self.op_types.take(node.into_portgraph())
490 }
491
492 fn remove_subtree(&mut self, node: Node) {
493 panic_invalid_non_entrypoint(self, node);
494 let mut queue = VecDeque::new();
495 queue.push_back(node);
496 while let Some(n) = queue.pop_front() {
497 queue.extend(self.children(n));
498 self.remove_node(n);
499 }
500 }
501
502 fn connect(
503 &mut self,
504 src: Node,
505 src_port: impl Into<OutgoingPort>,
506 dst: Node,
507 dst_port: impl Into<IncomingPort>,
508 ) {
509 let src_port = src_port.into();
510 let dst_port = dst_port.into();
511 panic_invalid_port(self, src, src_port);
512 panic_invalid_port(self, dst, dst_port);
513 self.graph
514 .link_nodes(
515 src.into_portgraph(),
516 src_port.index(),
517 dst.into_portgraph(),
518 dst_port.index(),
519 )
520 .expect("The ports should exist at this point.");
521 }
522
523 fn disconnect(&mut self, node: Node, port: impl Into<Port>) {
524 let port = port.into();
525 let offset = port.pg_offset();
526 panic_invalid_port(self, node, port);
527 let port = self
528 .graph
529 .port_index(node.into_portgraph(), offset)
530 .expect("The port should exist at this point.");
531 self.graph.unlink_port(port);
532 }
533
534 fn add_other_edge(&mut self, src: Node, dst: Node) -> (OutgoingPort, IncomingPort) {
535 let src_port = self
536 .get_optype(src)
537 .other_output_port()
538 .expect("Source operation has no non-dataflow outgoing edges");
539 let dst_port = self
540 .get_optype(dst)
541 .other_input_port()
542 .expect("Destination operation has no non-dataflow incoming edges");
543 self.connect(src, src_port, dst, dst_port);
544 (src_port, dst_port)
545 }
546
547 fn insert_forest(
548 &mut self,
549 mut other: Hugr,
550 root_parents: impl IntoIterator<Item = (Node, Self::Node)>,
551 ) -> InsertForestResult<Node, Self::Node> {
552 let roots: HashMap<_, _> = root_parents.into_iter().collect();
553 for &subtree in roots.keys() {
554 let mut n = subtree;
555 while let Some(parent) = other.get_parent(n) {
556 if roots.contains_key(&parent) {
557 return Err(InsertForestError::SubtreeAlreadyCopied { subtree, parent });
558 }
559 n = parent;
560 }
561 }
562 let inserted = insert_forest_internal(
563 self,
564 &other,
565 roots.keys().flat_map(|n| other.descendants(*n)),
566 roots.iter().map(|(r, p)| (*r, *p)),
567 )
568 .expect("Trees disjoint so no repeated nodes");
569 self.extensions.extend(other.extensions());
571 for (&node, &new_node) in &inserted.node_map {
575 let node_pg = node.into_portgraph();
576 let new_node_pg = new_node.into_portgraph();
577 let optype = other.op_types.take(node_pg);
578 self.op_types.set(new_node_pg, optype);
579 let meta = other.metadata.take(node_pg);
580 self.metadata.set(new_node_pg, meta);
581 }
582 Ok(inserted)
583 }
584
585 fn insert_view_forest<H: HugrView>(
586 &mut self,
587 other: &H,
588 nodes: impl Iterator<Item = H::Node> + Clone,
589 root_parents: impl IntoIterator<Item = (H::Node, Self::Node)>,
590 ) -> InsertForestResult<H::Node, Self::Node> {
591 let inserted = insert_forest_internal(self, other, nodes, root_parents.into_iter())?;
592 self.extensions.extend(other.extensions());
594 for (&node, &new_node) in &inserted.node_map {
598 let nodetype = other.get_optype(node);
599 self.op_types
600 .set(new_node.into_portgraph(), nodetype.clone());
601 let meta = other.node_metadata_map(node);
602 if !meta.is_empty() {
603 self.metadata
604 .set(new_node.into_portgraph(), Some(meta.clone()));
605 }
606 }
607 Ok(inserted)
608 }
609
610 fn copy_descendants(
611 &mut self,
612 root: Self::Node,
613 new_parent: Self::Node,
614 subst: Option<Substitution>,
615 ) -> BTreeMap<Self::Node, Self::Node> {
616 let mut descendants = self.hierarchy.descendants(root.into_portgraph());
617 let root2 = descendants.next();
618 debug_assert_eq!(root2, Some(root.into_portgraph()));
619 let nodes = Vec::from_iter(descendants);
620 let node_map = portgraph::view::Subgraph::with_nodes(&mut self.graph, nodes)
621 .copy_in_parent()
622 .expect("Is a MultiPortGraph");
623 let node_map =
624 translate_indices(Into::into, Into::into, node_map).collect::<BTreeMap<_, _>>();
625
626 for node in self.children(root).collect::<Vec<_>>() {
627 self.set_parent(*node_map.get(&node).unwrap(), new_parent);
628 }
629
630 for (&node, &new_node) in &node_map {
632 for ch in self.children(node).collect::<Vec<_>>() {
633 self.set_parent(*node_map.get(&ch).unwrap(), new_node);
634 }
635 let new_optype = match (&subst, self.get_optype(node)) {
636 (None, op) => op.clone(),
637 (Some(subst), op) => op.substitute(subst),
638 };
639 self.op_types.set(new_node.into_portgraph(), new_optype);
640 let meta = self.metadata.get(node.into_portgraph()).clone();
641 self.metadata.set(new_node.into_portgraph(), meta);
642 }
643 node_map
644 }
645
646 #[inline]
647 fn use_extension(&mut self, extension: impl Into<Arc<Extension>>) {
648 self.extensions_mut().register_updated(extension);
649 }
650
651 #[inline]
652 fn use_extensions<Reg>(&mut self, registry: impl IntoIterator<Item = Reg>)
653 where
654 ExtensionRegistry: Extend<Reg>,
655 {
656 self.extensions_mut().extend(registry);
657 }
658}
659
660fn insert_forest_internal<H: HugrView>(
677 hugr: &mut Hugr,
678 other: &H,
679 other_nodes: impl Iterator<Item = H::Node> + Clone,
680 root_parents: impl Iterator<Item = (H::Node, Node)>,
681) -> InsertForestResult<H::Node, Node> {
682 let new_node_count_hint = other_nodes.size_hint().1.unwrap_or_default();
683
684 let mut node_map = HashMap::with_capacity(new_node_count_hint);
686 hugr.reserve(new_node_count_hint, 0);
687
688 for old in other_nodes.clone() {
689 let op = OpType::default();
692 let new = hugr.add_node(op);
693 if node_map.insert(old, new).is_some() {
694 return Err(InsertForestError::DuplicateNode(old));
695 }
696
697 hugr.set_num_ports(new, other.num_inputs(old), other.num_outputs(old));
698
699 for tgt in other.node_inputs(old) {
701 for (neigh, src) in other.linked_outputs(old, tgt) {
702 let Some(&neigh) = node_map.get(&neigh) else {
703 continue;
704 };
705 hugr.connect(neigh, src, new, tgt);
706 }
707 }
708 for src in other.node_outputs(old) {
709 for (neigh, tgt) in other.linked_inputs(old, src) {
710 if neigh == old {
711 continue;
712 }
713 let Some(&neigh) = node_map.get(&neigh) else {
714 continue;
715 };
716 hugr.connect(new, src, neigh, tgt);
717 }
718 }
719 }
720 for (r, p) in root_parents {
721 hugr.set_parent(node_map[&r], p);
722 }
723 for old in other_nodes {
724 let new = node_map[&old];
725 if hugr.get_parent(new).is_none() {
726 let old_parent = other.get_parent(old).unwrap();
727 let new_parent = node_map[&old_parent];
728 hugr.set_parent(new, new_parent);
729 }
730 }
731 Ok(InsertedForest { node_map })
732}
733
734#[cfg(test)]
735pub(super) mod test {
736 use cool_asserts::assert_matches;
737 use itertools::Itertools;
738 use rstest::rstest;
739
740 use crate::builder::test::{dfg_calling_defn_decl, simple_dfg_hugr};
741
742 use crate::extension::PRELUDE;
743 use crate::extension::prelude::{Noop, usize_t};
744 use crate::hugr::ValidationError;
745 use crate::ops::handle::{FuncID, NodeHandle};
746 use crate::ops::{self, FuncDefn, Input, Output, dataflow::IOTrait};
747 use crate::types::Signature;
748
749 use super::*;
750
751 #[test]
752 fn simple_function() -> Result<(), Box<dyn std::error::Error>> {
753 let mut hugr = Hugr::default();
754 hugr.use_extension(PRELUDE.to_owned());
755
756 let module: Node = hugr.entrypoint();
758
759 let f: Node = hugr.add_node_with_parent(
761 module,
762 ops::FuncDefn::new(
763 "main",
764 Signature::new(usize_t(), vec![usize_t(), usize_t()]),
765 ),
766 );
767
768 {
769 let f_in = hugr.add_node_with_parent(f, ops::Input::new(vec![usize_t()]));
770 let f_out = hugr.add_node_with_parent(f, ops::Output::new(vec![usize_t(), usize_t()]));
771 let noop = hugr.add_node_with_parent(f, Noop(usize_t()));
772
773 hugr.connect(f_in, 0, noop, 0);
774 hugr.connect(noop, 0, f_out, 0);
775 hugr.connect(noop, 0, f_out, 1);
776 }
777
778 hugr.validate()?;
779
780 Ok(())
781 }
782
783 #[test]
784 fn metadata() {
785 let mut hugr = Hugr::default();
786
787 let root: Node = hugr.entrypoint();
789
790 assert_eq!(hugr.get_metadata(root, "meta"), None);
791
792 *hugr.get_metadata_mut(root, "meta") = "test".into();
793 assert_eq!(hugr.get_metadata(root, "meta"), Some(&"test".into()));
794
795 hugr.set_metadata(root, "meta", "new");
796 assert_eq!(hugr.get_metadata(root, "meta"), Some(&"new".into()));
797
798 hugr.remove_metadata(root, "meta");
799 assert_eq!(hugr.get_metadata(root, "meta"), None);
800 }
801
802 #[test]
803 fn remove_subtree() {
804 let mut hugr = Hugr::default();
805 hugr.use_extension(PRELUDE.to_owned());
806 let root = hugr.entrypoint();
807 let [foo, bar] = ["foo", "bar"].map(|name| {
808 let fd = hugr
809 .add_node_with_parent(root, FuncDefn::new(name, Signature::new_endo(usize_t())));
810 let inp = hugr.add_node_with_parent(fd, Input::new(usize_t()));
811 let out = hugr.add_node_with_parent(fd, Output::new(usize_t()));
812 hugr.connect(inp, 0, out, 0);
813 fd
814 });
815 hugr.validate().unwrap();
816 assert_eq!(hugr.num_nodes(), 7);
817
818 hugr.remove_subtree(foo);
819 hugr.validate().unwrap();
820 assert_eq!(hugr.num_nodes(), 4);
821
822 hugr.remove_subtree(bar);
823 hugr.validate().unwrap();
824 assert_eq!(hugr.num_nodes(), 1);
825 }
826
827 pub(in crate::hugr) fn check_calls_defn_decl(h: &Hugr, call1_defn: bool, call2_decl: bool) {
828 if call1_defn && call2_decl {
829 h.validate().unwrap();
830 } else {
831 assert!(matches!(
832 h.validate(),
833 Err(ValidationError::UnconnectedPort { .. })
834 ));
835 }
836 assert_eq!(
837 h.children(h.module_root()).count(),
838 1 + (call1_defn as usize) + (call2_decl as usize)
839 );
840 let [call1, call2] = h
841 .nodes()
842 .filter(|n| h.get_optype(*n).is_call())
843 .collect_array()
844 .unwrap();
845
846 let tgt1 = h.nodes().find(|n| {
847 h.get_optype(*n)
848 .as_func_defn()
849 .is_some_and(|fd| fd.func_name() == "helper_id")
850 });
851 assert_eq!(tgt1.is_some(), call1_defn);
852 assert_eq!(h.static_source(call1), tgt1);
853
854 let tgt2 = h.nodes().find(|n| {
855 h.get_optype(*n)
856 .as_func_decl()
857 .is_some_and(|fd| fd.func_name() == "helper2")
858 });
859 assert_eq!(tgt2.is_some(), call2_decl);
860 assert_eq!(h.static_source(call2), tgt2);
861 }
862
863 #[rstest]
864 fn test_insert_forest(
865 dfg_calling_defn_decl: (Hugr, FuncID<true>, FuncID<false>),
866 #[values(false, true)] copy_defn: bool,
867 #[values(false, true)] copy_decl: bool,
868 ) {
869 let (insert, defn, decl) = dfg_calling_defn_decl;
870 let mut h = simple_dfg_hugr();
871 let roots = std::iter::once((insert.entrypoint(), h.entrypoint()))
872 .chain(copy_defn.then_some((defn.node(), h.module_root())))
873 .chain(copy_decl.then_some((decl.node(), h.module_root())));
874 h.insert_forest(insert, roots).unwrap();
875 check_calls_defn_decl(&h, copy_defn, copy_decl);
876 }
877
878 #[rstest]
879 fn test_insert_view_forest(dfg_calling_defn_decl: (Hugr, FuncID<true>, FuncID<false>)) {
880 let (insert, defn, decl) = dfg_calling_defn_decl;
881 let mut h = simple_dfg_hugr();
882
883 let mut roots = HashMap::from([
884 (insert.entrypoint(), h.entrypoint()),
885 (defn.node(), h.module_root()),
886 (decl.node(), h.module_root()),
887 ]);
888
889 h.insert_view_forest(
891 &insert,
892 insert
893 .entry_descendants()
894 .chain(insert.descendants(defn.node()))
895 .chain(std::iter::once(decl.node())),
896 roots.clone(),
897 )
898 .unwrap();
899 h.validate().unwrap();
900
901 let mut h = simple_dfg_hugr();
903 let node_map = h
904 .insert_view_forest(
905 &insert,
906 insert.entry_descendants().chain([defn.node(), decl.node()]),
907 roots.clone(),
908 )
909 .unwrap()
910 .node_map;
911 assert_matches!(h.validate(),
912 Err(ValidationError::ContainerWithoutChildren { node, optype: _ }) => assert_eq!(node, node_map[&defn.node()]));
913
914 let func_containing_entry = insert.get_parent(insert.entrypoint()).unwrap();
916 assert!(matches!(
917 insert.get_optype(func_containing_entry),
918 OpType::FuncDefn(_)
919 ));
920 roots.insert(func_containing_entry, h.module_root());
921 let mut h = simple_dfg_hugr();
922 let node_map = h
923 .insert_view_forest(&insert, insert.nodes().skip(1), roots)
924 .unwrap()
925 .node_map;
926 assert!(matches!(
927 h.validate(),
928 Err(ValidationError::InterGraphEdgeError(_))
929 ));
930 for c in h.nodes().filter(|n| h.get_optype(*n).is_call()) {
931 assert!(h.static_source(c).is_some());
932 }
933 let inserted_ep = node_map[&insert.entrypoint()];
935 assert_eq!(h.get_parent(inserted_ep), Some(h.entrypoint()));
936 let new_defn = node_map[&func_containing_entry];
937 assert_eq!(h.children(new_defn).count(), 2);
938
939 let [inp, outp] = h.get_io(new_defn).unwrap();
940 assert!(matches!(h.get_optype(inp), OpType::Input(_)));
941 assert!(matches!(h.get_optype(outp), OpType::Output(_)));
942 assert_eq!(h.all_neighbours(inp).next(), None);
944 assert_eq!(h.input_neighbours(outp).next(), Some(inserted_ep));
945 }
946
947 #[rstest]
948 fn bad_insert_forest(dfg_calling_defn_decl: (Hugr, FuncID<true>, FuncID<false>)) {
949 let backup = simple_dfg_hugr();
950 let mut h = backup.clone();
951
952 let (insert, _, _) = dfg_calling_defn_decl;
953 let ep = insert.entrypoint();
954 let epp = insert.get_parent(ep).unwrap();
955 let roots = [(epp, h.module_root()), (ep, h.entrypoint())];
956 let r = h.insert_view_forest(
957 &insert,
958 insert.descendants(epp).chain(insert.descendants(ep)),
959 roots,
960 );
961 assert_eq!(r.err(), Some(InsertForestError::DuplicateNode(ep)));
962 assert!(h.validate().is_err());
963
964 let mut h = backup.clone();
965 let r = h.insert_forest(insert, roots);
966 assert_eq!(
967 r.err(),
968 Some(InsertForestError::SubtreeAlreadyCopied {
969 subtree: ep,
970 parent: epp
971 })
972 );
973 assert_eq!(h, backup);
975 }
976}