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