1use itertools::Itertools;
4
5use super::build_traits::{HugrBuilder, SubContainer};
6use super::handle::BuildHandle;
7use super::{BuildError, Container, Dataflow, DfgID, FuncID};
8
9use std::marker::PhantomData;
10
11use crate::hugr::internal::HugrMutInternals;
12use crate::hugr::{HugrView, ValidationError};
13use crate::ops::handle::NodeHandle;
14use crate::ops::{self, DFG, FuncDefn, NamedOp, OpParent, OpType};
15use crate::types::{PolyFuncType, Signature, Type};
16use crate::{Direction, Hugr, IncomingPort, Node, OutgoingPort, Visibility, Wire, hugr::HugrMut};
17
18#[derive(Debug, Clone, PartialEq)]
25pub struct DFGBuilder<T> {
26 pub(crate) base: T,
27 pub(crate) dfg_node: Node,
28 pub(crate) num_in_wires: usize,
29 pub(crate) num_out_wires: usize,
30}
31
32#[derive(Debug, Clone, PartialEq, derive_more::Display, derive_more::Error)]
34#[non_exhaustive]
35pub enum DFGAddPortError {
36 #[display("Adding port to an optype {op} is not supported.")]
38 ParentOpNotSupported {
39 op: String,
41 },
42}
43
44impl<T: AsMut<Hugr> + AsRef<Hugr>> DFGBuilder<T> {
45 pub fn create_with_io(
50 mut base: T,
51 parent: Node,
52 signature: Signature,
53 ) -> Result<Self, BuildError> {
54 debug_assert_eq!(base.as_ref().children(parent).count(), 0);
55
56 let num_in_wires = signature.input_count();
57 let num_out_wires = signature.output_count();
58 let input = ops::Input {
59 types: signature.input().clone(),
60 };
61 let output = ops::Output {
62 types: signature.output().clone(),
63 };
64 base.as_mut().add_node_with_parent(parent, input);
65 base.as_mut().add_node_with_parent(parent, output);
66
67 Ok(Self {
68 base,
69 dfg_node: parent,
70 num_in_wires,
71 num_out_wires,
72 })
73 }
74
75 pub fn create(base: T, parent: Node) -> Result<Self, BuildError> {
82 let sig = base
83 .as_ref()
84 .get_optype(parent)
85 .inner_function_type()
86 .expect("DFG parent must have an inner function signature.");
87 let num_in_wires = sig.input_count();
88 let num_out_wires = sig.output_count();
89
90 Ok(Self {
91 base,
92 dfg_node: parent,
93 num_in_wires,
94 num_out_wires,
95 })
96 }
97
98 pub fn add_input(&mut self, input_type: Type) -> Result<Wire, DFGAddPortError> {
111 let [inp_node, _] = self.io();
112
113 if !self.update_parent_signature(|mut s| {
115 s.input.to_mut().push(input_type.clone());
116 s
117 }) {
118 return Err(DFGAddPortError::ParentOpNotSupported {
119 op: self
120 .hugr()
121 .get_optype(self.container_node())
122 .name()
123 .to_string(),
124 });
125 }
126
127 let OpType::Input(inp) = self.hugr_mut().optype_mut(inp_node) else {
129 panic!("Input node {inp_node} is not an Input");
130 };
131 inp.types.to_mut().push(input_type);
132
133 let mut new_port = self.hugr_mut().add_ports(inp_node, Direction::Outgoing, 1);
134 let new_port = new_port.next().unwrap();
135
136 let new_value_port: OutgoingPort = (new_port - 1).into();
138 let new_order_port: OutgoingPort = new_port.into();
139 let order_edge_targets = self
140 .hugr()
141 .linked_inputs(inp_node, new_value_port)
142 .collect_vec();
143 self.hugr_mut().disconnect(inp_node, new_value_port);
144 for (tgt_node, tgt_port) in order_edge_targets {
145 self.hugr_mut()
146 .connect(inp_node, new_order_port, tgt_node, tgt_port);
147 }
148
149 self.num_in_wires += 1;
151
152 Ok(self.input_wires().next_back().unwrap())
153 }
154
155 pub fn add_output(&mut self, output_type: Type) -> Result<(), DFGAddPortError> {
166 let [_, out_node] = self.io();
167
168 if !self.update_parent_signature(|mut s| {
170 s.output.to_mut().push(output_type.clone());
171 s
172 }) {
173 return Err(DFGAddPortError::ParentOpNotSupported {
174 op: self
175 .hugr()
176 .get_optype(self.container_node())
177 .name()
178 .to_string(),
179 });
180 }
181
182 let OpType::Output(out) = self.hugr_mut().optype_mut(out_node) else {
184 panic!("Output node {out_node} is not an Output");
185 };
186 out.types.to_mut().push(output_type);
187
188 let mut new_port = self.hugr_mut().add_ports(out_node, Direction::Incoming, 1);
189 let new_port = new_port.next().unwrap();
190
191 let new_value_port: IncomingPort = (new_port - 1).into();
193 let new_order_port: IncomingPort = new_port.into();
194 let order_edge_sources = self
195 .hugr()
196 .linked_outputs(out_node, new_value_port)
197 .collect_vec();
198 self.hugr_mut().disconnect(out_node, new_value_port);
199 for (src_node, src_port) in order_edge_sources {
200 self.hugr_mut()
201 .connect(src_node, src_port, out_node, new_order_port);
202 }
203
204 self.num_out_wires += 1;
206
207 Ok(())
208 }
209
210 fn update_parent_signature(&mut self, f: impl FnOnce(Signature) -> Signature) -> bool {
221 let parent = self.container_node();
222
223 match self.hugr_mut().optype_mut(parent) {
224 ops::OpType::FuncDefn(fd) => {
225 let mut sig = std::mem::take(fd.signature_mut());
226 let body = std::mem::take(sig.body_mut());
227 *sig.body_mut() = f(body);
228 *fd.signature_mut() = sig;
229 }
230 ops::OpType::DFG(dfg) => {
231 let sig = std::mem::take(&mut dfg.signature);
232 dfg.signature = f(sig);
233 }
234 ops::OpType::DataflowBlock(dfb) => {
235 let inp = std::mem::take(&mut dfb.inputs);
236 let other_outputs = std::mem::take(&mut dfb.other_outputs);
237 let sig = f(Signature::new(inp, other_outputs));
238 dfb.inputs = sig.input;
239 dfb.other_outputs = sig.output;
240 }
241 _ => return false,
242 }
243 true
244 }
245}
246
247impl DFGBuilder<Hugr> {
248 pub fn new(signature: Signature) -> Result<DFGBuilder<Hugr>, BuildError> {
255 let dfg_op: DFG = ops::DFG {
256 signature: signature.clone(),
257 };
258 let base = Hugr::new_with_entrypoint(dfg_op).expect("DFG entrypoint should be valid");
259 let root = base.entrypoint();
260 DFGBuilder::create_with_io(base, root, signature)
261 }
262}
263
264impl HugrBuilder for DFGBuilder<Hugr> {
265 fn finish_hugr(self) -> Result<Hugr, ValidationError<Node>> {
266 self.base.validate()?;
267 Ok(self.base)
268 }
269}
270
271impl<T: AsMut<Hugr> + AsRef<Hugr>> Container for DFGBuilder<T> {
272 #[inline]
273 fn container_node(&self) -> Node {
274 self.dfg_node
275 }
276
277 #[inline]
278 fn hugr_mut(&mut self) -> &mut Hugr {
279 self.base.as_mut()
280 }
281
282 #[inline]
283 fn hugr(&self) -> &Hugr {
284 self.base.as_ref()
285 }
286}
287
288impl<T: AsMut<Hugr> + AsRef<Hugr>> SubContainer for DFGBuilder<T> {
289 type ContainerHandle = BuildHandle<DfgID>;
290 #[inline]
291 fn finish_sub_container(self) -> Result<Self::ContainerHandle, BuildError> {
292 Ok((self.dfg_node, self.num_out_wires).into())
293 }
294}
295
296impl<T: AsMut<Hugr> + AsRef<Hugr>> Dataflow for DFGBuilder<T> {
297 #[inline]
298 fn num_inputs(&self) -> usize {
299 self.num_in_wires
300 }
301}
302
303#[derive(Debug, Clone, PartialEq)]
306pub struct DFGWrapper<B, T>(DFGBuilder<B>, PhantomData<T>);
307
308impl<B, T: NodeHandle> DFGWrapper<B, T> {
309 pub fn from_dfg_builder(db: DFGBuilder<B>) -> Self {
314 Self(db, PhantomData)
315 }
316
317 pub fn into_dfg_builder(self) -> DFGBuilder<B> {
319 self.0
320 }
321}
322
323impl<B: AsMut<Hugr> + AsRef<Hugr>, T> DFGWrapper<B, T> {
324 pub fn add_input(&mut self, input_type: Type) -> Result<Wire, DFGAddPortError> {
340 self.0.add_input(input_type)
341 }
342
343 pub fn add_output(&mut self, output_type: Type) -> Result<(), DFGAddPortError> {
355 self.0.add_output(output_type)
356 }
357}
358
359pub type FunctionBuilder<B> = DFGWrapper<B, BuildHandle<FuncID<true>>>;
361
362impl FunctionBuilder<Hugr> {
363 pub fn new(
370 name: impl Into<String>,
371 signature: impl Into<PolyFuncType>,
372 ) -> Result<Self, BuildError> {
373 Self::new_with_op(FuncDefn::new(name, signature))
374 }
375
376 pub fn new_vis(
383 name: impl Into<String>,
384 signature: impl Into<PolyFuncType>,
385 visibility: Visibility,
386 ) -> Result<Self, BuildError> {
387 Self::new_with_op(FuncDefn::new_vis(name, signature, visibility))
388 }
389
390 fn new_with_op(op: FuncDefn) -> Result<Self, BuildError> {
391 let body = op.signature().body().clone();
392
393 let base = Hugr::new_with_entrypoint(op).expect("FuncDefn entrypoint should be valid");
394 let root = base.entrypoint();
395
396 let db = DFGBuilder::create_with_io(base, root, body)?;
397 Ok(Self::from_dfg_builder(db))
398 }
399}
400
401impl<B: AsMut<Hugr> + AsRef<Hugr>> FunctionBuilder<B> {
402 pub fn with_hugr(
410 mut hugr: B,
411 name: impl Into<String>,
412 signature: impl Into<PolyFuncType>,
413 ) -> Result<Self, BuildError> {
414 let signature: PolyFuncType = signature.into();
415 let body = signature.body().clone();
416 let op = ops::FuncDefn::new(name, signature);
417
418 let module = hugr.as_ref().module_root();
419 let func = hugr.as_mut().add_node_with_parent(module, op);
420
421 let db = DFGBuilder::create_with_io(hugr, func, body)?;
422 Ok(Self::from_dfg_builder(db))
423 }
424}
425
426impl<B: AsMut<Hugr> + AsRef<Hugr>, T> Container for DFGWrapper<B, T> {
427 #[inline]
428 fn container_node(&self) -> Node {
429 self.0.container_node()
430 }
431
432 #[inline]
433 fn hugr_mut(&mut self) -> &mut Hugr {
434 self.0.hugr_mut()
435 }
436
437 #[inline]
438 fn hugr(&self) -> &Hugr {
439 self.0.hugr()
440 }
441}
442
443impl<B: AsMut<Hugr> + AsRef<Hugr>, T> Dataflow for DFGWrapper<B, T> {
444 #[inline]
445 fn num_inputs(&self) -> usize {
446 self.0.num_inputs()
447 }
448}
449
450impl<B: AsMut<Hugr> + AsRef<Hugr>, T: From<BuildHandle<DfgID>>> SubContainer for DFGWrapper<B, T> {
451 type ContainerHandle = T;
452
453 #[inline]
454 fn finish_sub_container(self) -> Result<Self::ContainerHandle, BuildError> {
455 self.0.finish_sub_container().map(Into::into)
456 }
457}
458
459impl<T> HugrBuilder for DFGWrapper<Hugr, T> {
460 fn finish_hugr(self) -> Result<Hugr, ValidationError<Node>> {
461 self.0.finish_hugr()
462 }
463}
464
465#[cfg(test)]
466pub(crate) mod test {
467 use cool_asserts::assert_matches;
468 use rstest::rstest;
469 use std::collections::HashMap;
470
471 use crate::builder::build_traits::DataflowHugr;
472 use crate::builder::test::dfg_calling_defn_decl;
473 use crate::builder::{
474 BuilderWiringError, CFGBuilder, DataflowSubContainer, ModuleBuilder, TailLoopBuilder,
475 endo_sig, inout_sig,
476 };
477 use crate::extension::SignatureError;
478 use crate::extension::prelude::{Noop, bool_t, qb_t, usize_t};
479 use crate::hugr::linking::{NameLinkingPolicy, NodeLinkingDirective, OnMultiDefn};
480 use crate::hugr::validate::InterGraphEdgeError;
481 use crate::metadata::Metadata;
482 use crate::ops::{FuncDecl, FuncDefn, OpParent, OpTag, OpTrait, Value, handle::NodeHandle};
483 use crate::std_extensions::logic::test::and_op;
484 use crate::types::type_param::TypeParam;
485 use crate::types::{EdgeKind, FuncValueType, RowVariable, Signature, Type, TypeBound, TypeRV};
486 use crate::utils::test_quantum_extension::h_gate;
487 use crate::{Wire, builder::test::n_identity, type_row};
488
489 use super::super::test::simple_dfg_hugr;
490 use super::*;
491 #[test]
492 fn nested_identity() -> Result<(), BuildError> {
493 let build_result = {
494 let mut outer_builder = DFGBuilder::new(endo_sig(vec![usize_t(), qb_t()]))?;
495
496 let [int, qb] = outer_builder.input_wires_arr();
497
498 let q_out = outer_builder.add_dataflow_op(h_gate(), vec![qb])?;
499
500 let inner_builder = outer_builder.dfg_builder_endo([(usize_t(), int)])?;
501 let inner_id = n_identity(inner_builder)?;
502
503 outer_builder.finish_hugr_with_outputs(inner_id.outputs().chain(q_out.outputs()))
504 };
505
506 assert_eq!(build_result.err(), None);
507
508 Ok(())
509 }
510
511 fn copy_scaffold<F>(f: F, msg: &'static str) -> Result<(), BuildError>
513 where
514 F: FnOnce(&mut DFGBuilder<Hugr>) -> Result<(), BuildError>,
515 {
516 let build_result = {
517 let mut builder = DFGBuilder::new(inout_sig([bool_t()], vec![bool_t(); 2]))?;
518
519 f(&mut builder)?;
520
521 builder.finish_hugr()
522 };
523 assert_matches!(build_result, Ok(_), "Failed on example: {}", msg);
524
525 Ok(())
526 }
527 #[test]
528 fn copy_insertion() -> Result<(), BuildError> {
529 copy_scaffold(
530 |f_build| {
531 let [b1] = f_build.input_wires_arr();
532 f_build.set_outputs([b1, b1])
533 },
534 "Copy input and output",
535 )?;
536
537 copy_scaffold(
538 |f_build| {
539 let [b1] = f_build.input_wires_arr();
540 let xor = f_build.add_dataflow_op(and_op(), [b1, b1])?;
541 f_build.set_outputs([xor.out_wire(0), b1])
542 },
543 "Copy input and use with binary function",
544 )?;
545
546 copy_scaffold(
547 |f_build| {
548 let [b1] = f_build.input_wires_arr();
549 let xor1 = f_build.add_dataflow_op(and_op(), [b1, b1])?;
550 let xor2 = f_build.add_dataflow_op(and_op(), [b1, xor1.out_wire(0)])?;
551 f_build.set_outputs([xor2.out_wire(0), b1])
552 },
553 "Copy multiple times",
554 )?;
555
556 Ok(())
557 }
558
559 #[test]
560 fn copy_insertion_qubit() {
561 let builder = || {
562 let mut module_builder = ModuleBuilder::new();
563
564 let f_build = module_builder
565 .define_function("main", Signature::new(vec![qb_t()], vec![qb_t(), qb_t()]))?;
566
567 let [q1] = f_build.input_wires_arr();
568 f_build.finish_with_outputs([q1, q1])?;
569
570 Ok(module_builder.finish_hugr()?)
571 };
572
573 assert_matches!(
574 builder(),
575 Err(BuildError::OutputWiring {
576 error: BuilderWiringError::NoCopyLinear { typ, .. },
577 ..
578 })
579 if *typ == qb_t()
580 );
581 }
582
583 #[test]
584 fn simple_inter_graph_edge() {
585 let builder = || -> Result<Hugr, BuildError> {
586 let mut f_build =
587 FunctionBuilder::new("main", Signature::new(vec![bool_t()], vec![bool_t()]))?;
588
589 let [i1] = f_build.input_wires_arr();
590 let noop = f_build.add_dataflow_op(Noop(bool_t()), [i1])?;
591 let i1 = noop.out_wire(0);
592
593 let mut nested =
594 f_build.dfg_builder(Signature::new(type_row![], vec![bool_t()]), [])?;
595
596 let id = nested.add_dataflow_op(Noop(bool_t()), [i1])?;
597
598 let nested = nested.finish_with_outputs([id.out_wire(0)])?;
599
600 f_build.finish_hugr_with_outputs([nested.out_wire(0)])
601 };
602
603 assert_matches!(builder(), Ok(_));
604 }
605
606 #[rstest]
607 #[case::function(|sig| FunctionBuilder::new("main", sig).unwrap().into_dfg_builder())]
608 #[case::dfg(|sig| DFGBuilder::new(sig).unwrap())]
609 #[case::df_block(|sig: Signature| {
610 let outs = sig.output.clone();
611 let mut h = CFGBuilder::new(sig).unwrap();
612 let entry_node = h.entry_builder([], outs).unwrap().finish_sub_container().unwrap().node();
613 let hugr = std::mem::take(h.hugr_mut());
614 DFGBuilder::create(hugr, entry_node).unwrap()
615 })]
616 fn add_inputs_outputs(#[case] builder: impl FnOnce(Signature) -> DFGBuilder<Hugr>) {
617 let builder = || -> Result<(Hugr, Node, Signature), BuildError> {
618 let mut dfg = builder(Signature::new(vec![bool_t()], vec![bool_t()]));
619 let dfg_node = dfg.container_node();
620
621 let initial_sig = dfg
623 .hugr()
624 .get_optype(dfg_node)
625 .inner_function_type()
626 .unwrap()
627 .into_owned();
628
629 let [i0] = dfg.input_wires_arr();
630 let noop0 = dfg.add_dataflow_op(Noop(bool_t()), [i0])?;
631
632 dfg.set_order(&dfg.io()[0], &noop0.node());
634 dfg.set_order(&noop0.node(), &dfg.io()[1]);
635
636 dfg.add_output(qb_t()).unwrap();
638 let i1 = dfg.add_input(qb_t()).unwrap();
639 let noop1 = dfg.add_dataflow_op(Noop(qb_t()), [i1])?;
640
641 dfg.set_outputs([noop0.out_wire(0), noop1.out_wire(0)])?;
643 let hugr = std::mem::take(dfg.hugr_mut());
644 Ok((hugr, dfg_node, initial_sig))
645 };
646
647 let (hugr, dfg_node, initial_sig) = builder().unwrap_or_else(|e| panic!("{e}"));
648
649 let container_sig = hugr.get_optype(dfg_node).inner_function_type().unwrap();
650 let mut expected_sig = initial_sig;
651 expected_sig.input.to_mut().push(qb_t());
652 expected_sig.output.to_mut().push(qb_t());
653 assert_eq!(
654 container_sig.io(),
655 (&expected_sig.input, &expected_sig.output),
656 "Got signature: {container_sig}, expected: {expected_sig}",
657 );
658 }
659
660 #[rstest]
661 #[case::tail_loop(|sig: Signature| TailLoopBuilder::new(sig.input, vec![], sig.output).unwrap().into_dfg_builder())]
662 fn add_inputs_outputs_unsupported(#[case] builder: impl FnOnce(Signature) -> DFGBuilder<Hugr>) {
663 let mut dfg = builder(Signature::new(vec![bool_t()], vec![bool_t()]));
664
665 assert!(dfg.add_output(qb_t()).is_err());
667 assert!(dfg.add_input(qb_t()).is_err());
668 }
669
670 #[test]
671 fn error_on_linear_inter_graph_edge() -> Result<(), BuildError> {
672 let mut f_build = FunctionBuilder::new("main", Signature::new(vec![qb_t()], vec![qb_t()]))?;
673
674 let [i1] = f_build.input_wires_arr();
675 let noop = f_build.add_dataflow_op(Noop(qb_t()), [i1])?;
676 let i1 = noop.out_wire(0);
677
678 let mut nested = f_build.dfg_builder(Signature::new(type_row![], vec![qb_t()]), [])?;
679
680 let id_res = nested.add_dataflow_op(Noop(qb_t()), [i1]);
681
682 assert_matches!(
685 id_res.map(|bh| bh.handle().node()), Err(BuildError::OperationWiring {
687 error: BuilderWiringError::NonCopyableIntergraph { .. },
688 ..
689 })
690 );
691
692 Ok(())
693 }
694
695 #[rstest]
696 fn dfg_hugr(simple_dfg_hugr: Hugr) {
697 assert_eq!(simple_dfg_hugr.num_nodes(), 7);
698 assert_eq!(simple_dfg_hugr.entry_descendants().count(), 3);
699 assert_matches!(simple_dfg_hugr.entrypoint_optype().tag(), OpTag::Dfg);
700 }
701
702 #[test]
703 fn add_hugr() -> Result<(), BuildError> {
704 struct XIntMetadata;
705 impl Metadata for XIntMetadata {
706 type Type<'hugr> = u32;
707 const KEY: &'static str = "x";
708 }
709
710 struct XStringMetadata;
711 impl Metadata for XStringMetadata {
712 type Type<'hugr> = &'hugr str;
713 const KEY: &'static str = "x";
714 }
715
716 let mut dfg_builder = DFGBuilder::new(Signature::new_endo([bool_t()]))?;
718 let [i1] = dfg_builder.input_wires_arr();
719 dfg_builder.set_metadata::<XIntMetadata>(42);
720 let dfg_hugr = dfg_builder.finish_hugr_with_outputs([i1])?;
721
722 let mut module_builder = ModuleBuilder::new();
724
725 let (dfg_node, f_node) = {
726 let mut f_build =
727 module_builder.define_function("main", Signature::new_endo([bool_t()]))?;
728
729 let [i1] = f_build.input_wires_arr();
730 let dfg = f_build.add_hugr_with_wires(dfg_hugr, [i1])?;
731 let f = f_build.finish_with_outputs([dfg.out_wire(0)])?;
732 module_builder.set_child_metadata::<XStringMetadata>(f.node(), "hi");
733 (dfg.node(), f.node())
734 };
735
736 let hugr = module_builder.finish_hugr()?;
737 assert_eq!(hugr.entry_descendants().count(), 7);
738
739 assert_eq!(hugr.get_metadata::<XIntMetadata>(hugr.entrypoint()), None);
740 assert_eq!(hugr.get_metadata::<XIntMetadata>(dfg_node), Some(42));
741 assert_eq!(hugr.get_metadata::<XStringMetadata>(f_node), Some("hi"));
742
743 Ok(())
744 }
745
746 #[rstest]
747 fn add_link_hugr_by_node(
748 #[values(false, true)] replace: bool,
749 #[values(true, false)] view: bool,
750 ) {
751 let mut fb = FunctionBuilder::new("main", Signature::new_endo([bool_t()])).unwrap();
752 let my_decl = fb
753 .module_root_builder()
754 .declare("func1", Signature::new_endo([bool_t()]).into())
755 .unwrap();
756 let (insert, ins_defn, ins_decl) = dfg_calling_defn_decl();
757 let ins_defn_name = insert
758 .get_optype(ins_defn.node())
759 .as_func_defn()
760 .unwrap()
761 .func_name()
762 .clone();
763 let ins_decl_name = insert
764 .get_optype(ins_decl.node())
765 .as_func_decl()
766 .unwrap()
767 .func_name()
768 .clone();
769 let decl_mode = if replace {
770 NodeLinkingDirective::UseExisting(my_decl.node())
771 } else {
772 NodeLinkingDirective::add()
773 };
774 let link_spec = HashMap::from([
775 (ins_defn.node(), NodeLinkingDirective::add()),
776 (ins_decl.node(), decl_mode),
777 ]);
778 let inserted = if view {
779 fb.add_link_view_by_node_with_wires(&insert, [], link_spec)
780 .unwrap()
781 } else {
782 fb.add_link_hugr_by_node_with_wires(insert, [], link_spec)
783 .unwrap()
784 };
785 let h = fb.finish_hugr_with_outputs(inserted.outputs()).unwrap();
786 let defn_names = h
787 .nodes()
788 .filter_map(|n| h.get_optype(n).as_func_defn().map(FuncDefn::func_name))
789 .collect_vec();
790 assert_eq!(defn_names, [&"main".to_string(), &ins_defn_name]);
791 let decl_names = h
792 .nodes()
793 .filter_map(|n| h.get_optype(n).as_func_decl().map(FuncDecl::func_name))
794 .cloned()
795 .collect_vec();
796 let mut expected_decl_names = vec!["func1".to_string()];
797 if !replace {
798 expected_decl_names.push(ins_decl_name)
799 }
800 assert_eq!(decl_names, expected_decl_names);
801 }
802
803 #[test]
804 fn add_link_hugr() {
805 let to_insert = {
806 let mut dfb = DFGBuilder::new(endo_sig(vec![usize_t(); 2])).unwrap();
807 let mut mb = dfb.module_root_builder();
808 let fb = mb
809 .define_function_vis("foo", endo_sig([usize_t()]), Visibility::Public)
810 .unwrap();
811 let ins = fb.input_wires();
812 let func = fb.finish_with_outputs(ins).unwrap();
813 let [in1, in2] = dfb.input_wires_arr();
814 let [out1] = dfb.call(func.handle(), &[], [in1]).unwrap().outputs_arr();
815 let [out2] = dfb.call(func.handle(), &[], [in2]).unwrap().outputs_arr();
816 dfb.finish_hugr_with_outputs([out1, out2]).unwrap()
817 };
818 let mut dfb = DFGBuilder::new(inout_sig([usize_t()], vec![usize_t(); 2])).unwrap();
819 let [in1] = dfb.input_wires_arr();
820 let pol = NameLinkingPolicy::default().on_multiple_defn(OnMultiDefn::UseTarget);
821 let [out1, out2] = dfb
822 .add_link_view_with_wires(&to_insert, &pol, [in1, in1])
823 .unwrap()
824 .outputs_arr();
825 assert!({
826 let h = dfb.hugr();
827 h.children(h.module_root())
828 .skip(1)
829 .exactly_one()
830 .is_ok_and(|n| h.static_targets(n).unwrap().count() == 2)
831 });
832 let [out3, out4] = dfb
833 .add_link_hugr_with_wires(to_insert, &pol, [out1, out2])
834 .unwrap()
835 .outputs_arr();
836 let h = dfb.finish_hugr_with_outputs([out3, out4]).unwrap();
837 assert!(
838 h.children(h.module_root())
839 .skip(1)
840 .exactly_one()
841 .is_ok_and(|n| h.static_targets(n).unwrap().count() == 4)
842 );
843 }
844
845 #[test]
846 fn barrier_node() -> Result<(), BuildError> {
847 let mut parent = DFGBuilder::new(endo_sig([bool_t()]))?;
848
849 let [w] = parent.input_wires_arr();
850
851 let mut dfg_b = parent.dfg_builder(endo_sig([bool_t()]), [w])?;
852 let [w] = dfg_b.input_wires_arr();
853
854 let barr0 = dfg_b.add_barrier([w])?;
855 let [w] = barr0.outputs_arr();
856
857 let barr1 = dfg_b.add_barrier([w])?;
858 let [w] = barr1.outputs_arr();
859
860 let dfg = dfg_b.finish_with_outputs([w])?;
861 let [w] = dfg.outputs_arr();
862
863 let mut dfg2_b = parent.dfg_builder(endo_sig(vec![bool_t(), bool_t()]), [w, w])?;
864 let [w1, w2] = dfg2_b.input_wires_arr();
865 let barr2 = dfg2_b.add_barrier([w1, w2])?;
866 let wires: Vec<Wire> = barr2.outputs().collect();
867
868 let dfg2 = dfg2_b.finish_with_outputs(wires)?;
869 let [w, _] = dfg2.outputs_arr();
870 parent.finish_hugr_with_outputs([w])?;
871
872 Ok(())
873 }
874
875 #[test]
876 fn non_cfg_ancestor() -> Result<(), BuildError> {
877 let unit_sig = Signature::new_endo([Type::UNIT]);
878 let mut b = DFGBuilder::new(unit_sig.clone())?;
879 let b_child = b.dfg_builder(unit_sig.clone(), b.input_wires())?;
880 let [b_child_in_wire] = b_child.input_wires_arr();
881 b_child.finish_with_outputs([b_child_in_wire])?;
882 let b_child_2 = b.dfg_builder(Signature::new([], [Type::UNIT]), [])?;
883
884 let b_child_2_handle = b_child_2.finish_with_outputs([b_child_in_wire])?;
887
888 let res = b.finish_hugr_with_outputs([b_child_2_handle.out_wire(0)]);
889
890 assert_matches!(
891 res,
892 Err(BuildError::InvalidHUGR(
893 ValidationError::InterGraphEdgeError(InterGraphEdgeError::NonCFGAncestor { .. })
894 ))
895 );
896 Ok(())
897 }
898
899 #[test]
900 fn no_relation_edge() -> Result<(), BuildError> {
901 let unit_sig = Signature::new(type_row![Type::UNIT], type_row![Type::UNIT]);
902 let mut b = DFGBuilder::new(unit_sig.clone())?;
903 let mut b_child = b.dfg_builder(unit_sig.clone(), [b.input().out_wire(0)])?;
904 let b_child_child = b_child.dfg_builder(unit_sig.clone(), [b_child.input().out_wire(0)])?;
905 let b_child_child_in_wire = b_child_child.input().out_wire(0);
906
907 b_child_child.finish_with_outputs([])?;
908 b_child.finish_with_outputs([])?;
909
910 let mut b_child_2 = b.dfg_builder(unit_sig.clone(), [])?;
911 let b_child_2_child =
912 b_child_2.dfg_builder(unit_sig.clone(), [b_child_2.input().out_wire(0)])?;
913
914 let res = b_child_2_child.finish_with_outputs([b_child_child_in_wire]);
915
916 assert_matches!(
917 res.map(|h| h.handle().node()), Err(BuildError::OutputWiring {
919 error: BuilderWiringError::NoRelationIntergraph { .. },
920 ..
921 })
922 );
923 Ok(())
924 }
925
926 #[test]
927 fn no_outer_row_variables() -> Result<(), BuildError> {
928 let e = crate::hugr::validate::test::extension_with_eval_parallel();
929 let tv = TypeRV::new_row_var_use(0, TypeBound::Copyable);
930 FunctionBuilder::new(
932 "bad_eval",
933 PolyFuncType::new(
934 [TypeParam::new_list_type(TypeBound::Copyable)],
935 Signature::new(
936 [Type::new_function(FuncValueType::new(
937 [usize_t()],
938 [tv.clone()],
939 ))],
940 [],
941 ),
942 ),
943 )?;
944
945 let ev = e.instantiate_extension_op(
947 "eval",
948 [vec![usize_t().into()].into(), vec![tv.into()].into()],
949 );
950 assert_eq!(
951 ev,
952 Err(SignatureError::RowVarWhereTypeExpected {
953 var: RowVariable(0, TypeBound::Copyable)
954 })
955 );
956 Ok(())
957 }
958
959 #[test]
960 fn order_edges() {
961 let (mut hugr, load_constant, call) = {
962 let mut builder = ModuleBuilder::new();
963 let func = builder
964 .declare("func", Signature::new_endo([bool_t()]).into())
965 .unwrap();
966 let (load_constant, call) = {
967 let mut builder = builder
968 .define_function("main", Signature::new(Type::EMPTY_TYPEROW, [bool_t()]))
969 .unwrap();
970 let load_constant = builder.add_load_value(Value::true_val());
971 let [r] = builder
972 .call(&func, &[], [load_constant])
973 .unwrap()
974 .outputs_arr();
975 builder.finish_with_outputs([r]).unwrap();
976 (load_constant.node(), r.node())
977 };
978 (builder.finish_hugr().unwrap(), load_constant, call)
979 };
980
981 let lc_optype = hugr.get_optype(load_constant);
982 let call_optype = hugr.get_optype(call);
983 assert_eq!(EdgeKind::StateOrder, lc_optype.other_input().unwrap());
984 assert_eq!(EdgeKind::StateOrder, lc_optype.other_output().unwrap());
985 assert_eq!(EdgeKind::StateOrder, call_optype.other_input().unwrap());
986 assert_eq!(EdgeKind::StateOrder, call_optype.other_output().unwrap());
987
988 hugr.connect(
989 load_constant,
990 lc_optype.other_output_port().unwrap(),
991 call,
992 call_optype.other_input_port().unwrap(),
993 );
994
995 hugr.validate().unwrap();
996 }
997}