1use thiserror::Error;
89
90use crate::extension::SignatureError;
91use crate::extension::simple_op::OpLoadError;
92use crate::hugr::ValidationError;
93use crate::hugr::linking::{NameLinkingError, NodeLinkingError};
94use crate::ops::handle::{BasicBlockID, CfgID, ConditionalID, DfgID, FuncID, TailLoopID};
95use crate::ops::{NamedOp, OpType};
96use crate::types::Type;
97use crate::types::{ConstTypeError, Signature, TypeRow};
98use crate::{Node, Port, Wire};
99
100pub mod handle;
101pub use handle::BuildHandle;
102
103mod build_traits;
104pub use build_traits::{
105 Container, Dataflow, DataflowHugr, DataflowSubContainer, HugrBuilder, SubContainer,
106};
107
108pub mod dataflow;
109pub use dataflow::{DFGBuilder, DFGWrapper, FunctionBuilder};
110
111mod module;
112pub use module::ModuleBuilder;
113
114mod cfg;
115pub use cfg::{BlockBuilder, CFGBuilder};
116
117mod tail_loop;
118pub use tail_loop::TailLoopBuilder;
119
120mod conditional;
121pub use conditional::{CaseBuilder, ConditionalBuilder};
122
123mod circuit;
124pub use circuit::{CircuitBuildError, CircuitBuilder};
125
126pub fn endo_sig(types: impl Into<TypeRow>) -> Signature {
128 Signature::new_endo(types)
129}
130
131pub fn inout_sig(inputs: impl Into<TypeRow>, outputs: impl Into<TypeRow>) -> Signature {
133 Signature::new(inputs, outputs)
134}
135
136#[derive(Debug, Clone, PartialEq, Error)]
137#[non_exhaustive]
138pub enum BuildError {
140 #[error("The constructed HUGR is invalid: {0}.")]
142 InvalidHUGR(#[from] ValidationError<Node>),
143 #[error(transparent)]
146 SignatureError(#[from] SignatureError),
147 #[error("Constant failed typechecking: {0}")]
151 BadConstant(#[from] ConstTypeError),
152 #[error("CFG entry node already built for CFG node: {0}.")]
154 EntryBuiltError(Node),
155 #[error(
158 "Cannot initialize hugr for a BasicBlockBuilder with complex sum-rows. Use a CFGBuilder instead."
159 )]
160 BasicBlockTooComplex,
161 #[error("Node with index {node} does not have type {op_desc} as expected.")]
163 UnexpectedType {
164 node: Node,
166 op_desc: &'static str,
168 },
169 #[error("Error building Conditional node: {0}.")]
171 ConditionalError(#[from] conditional::ConditionalBuildError),
172
173 #[error("{node} not found in the Hugr")]
175 NodeNotFound {
176 node: Node,
178 },
179
180 #[error("In inserting Hugr: {0}")]
182 HugrNodeLinkingError(#[from] NodeLinkingError<Node, Node>),
183
184 #[error{"In linking Hugr: {0}"}]
186 HugrLinkingError(#[from] NameLinkingError<Node, Node>),
187
188 #[error("In inserting HugrView: {0}")]
193 HugrViewInsertionError(String),
194
195 #[error("Wire not found in Hugr: {0}.")]
197 WireNotFound(Wire),
198
199 #[error("Error in CircuitBuilder: {0}.")]
201 CircuitError(#[from] circuit::CircuitBuildError),
202
203 #[error("Found an error while setting the outputs of a {} container, {container_node}. {error}", .container_op.name())]
205 #[allow(missing_docs)]
206 OutputWiring {
207 container_op: Box<OpType>,
208 container_node: Node,
209 #[source]
210 error: BuilderWiringError,
211 },
212
213 #[error("Got an input wire while adding a {} to the circuit. {error}", .op.name())]
217 #[allow(missing_docs)]
218 OperationWiring {
219 op: Box<OpType>,
220 #[source]
221 error: BuilderWiringError,
222 },
223
224 #[error("Failed to load an extension op: {0}")]
225 #[allow(missing_docs)]
226 ExtensionOp(#[from] OpLoadError),
227}
228
229#[derive(Debug, Clone, PartialEq, Error)]
230#[non_exhaustive]
231pub enum BuilderWiringError {
233 #[error("Cannot copy linear type {typ} from output {src_offset} of node {src}")]
235 #[allow(missing_docs)]
236 NoCopyLinear {
237 typ: Box<Type>,
238 src: Node,
239 src_offset: Port,
240 },
241 #[error(
243 "Cannot connect an inter-graph edge between unrelated nodes. Tried connecting {src} ({src_offset}) with {dst} ({dst_offset})."
244 )]
245 #[allow(missing_docs)]
246 NoRelationIntergraph {
247 src: Node,
248 src_offset: Port,
249 dst: Node,
250 dst_offset: Port,
251 },
252 #[error(
254 "Inter-graph edges cannot carry non-copyable data {typ}. Tried connecting {src} ({src_offset}) with {dst} ({dst_offset})."
255 )]
256 #[allow(missing_docs)]
257 NonCopyableIntergraph {
258 src: Node,
259 src_offset: Port,
260 dst: Node,
261 dst_offset: Port,
262 typ: Box<Type>,
263 },
264}
265
266#[cfg(test)]
267pub(crate) mod test {
268 use rstest::fixture;
269
270 use crate::Hugr;
271 use crate::extension::prelude::{bool_t, usize_t};
272 use crate::hugr::{HugrMut, views::HugrView};
273 use crate::ops;
274 use crate::package::Package;
275 use crate::types::{PolyFuncType, Signature};
276
277 use super::handle::BuildHandle;
278 use super::{
279 BuildError, CFGBuilder, DFGBuilder, Dataflow, DataflowHugr, FuncID, FunctionBuilder,
280 ModuleBuilder,
281 };
282 use super::{DataflowSubContainer, HugrBuilder};
283
284 pub(crate) fn n_identity<T: DataflowSubContainer>(
286 dataflow_builder: T,
287 ) -> Result<T::ContainerHandle, BuildError> {
288 let w = dataflow_builder.input_wires();
289 dataflow_builder.finish_with_outputs(w)
290 }
291
292 pub(crate) fn build_main(
293 signature: PolyFuncType,
294 f: impl FnOnce(FunctionBuilder<&mut Hugr>) -> Result<BuildHandle<FuncID<true>>, BuildError>,
295 ) -> Result<Hugr, BuildError> {
296 let mut module_builder = ModuleBuilder::new();
297 let f_builder = module_builder.define_function("main", signature)?;
298
299 f(f_builder)?;
300
301 Ok(module_builder.finish_hugr()?)
302 }
303
304 #[fixture]
305 pub(crate) fn simple_dfg_hugr() -> Hugr {
306 let dfg_builder = DFGBuilder::new(Signature::new(vec![bool_t()], vec![bool_t()])).unwrap();
307 let [i1] = dfg_builder.input_wires_arr();
308 dfg_builder.finish_hugr_with_outputs([i1]).unwrap()
309 }
310
311 #[fixture]
312 pub(crate) fn simple_funcdef_hugr() -> Hugr {
313 let fn_builder =
314 FunctionBuilder::new("test", Signature::new(vec![bool_t()], vec![bool_t()])).unwrap();
315 let [i1] = fn_builder.input_wires_arr();
316 fn_builder.finish_hugr_with_outputs([i1]).unwrap()
317 }
318
319 #[fixture]
320 pub(crate) fn simple_module_hugr() -> Hugr {
321 let mut builder = ModuleBuilder::new();
322 let sig = Signature::new(vec![bool_t()], vec![bool_t()]);
323 builder.declare("test", sig.into()).unwrap();
324 builder.finish_hugr().unwrap()
325 }
326
327 #[fixture]
328 pub(crate) fn simple_cfg_hugr() -> Hugr {
329 let mut cfg_builder =
330 CFGBuilder::new(Signature::new(vec![usize_t()], vec![usize_t()])).unwrap();
331 super::cfg::test::build_basic_cfg(&mut cfg_builder).unwrap();
332 cfg_builder.finish_hugr().unwrap()
333 }
334
335 #[fixture]
336 pub(crate) fn simple_package() -> Package {
337 let hugr = simple_module_hugr();
338 Package::new([hugr])
339 }
340
341 #[fixture]
342 pub(crate) fn multi_module_package() -> Package {
343 let hugr0 = simple_module_hugr();
344 let hugr1 = simple_module_hugr();
345 Package::new([hugr0, hugr1])
346 }
347
348 pub(crate) fn closed_dfg_root_hugr(signature: Signature) -> Hugr {
352 let mut hugr = Hugr::new_with_entrypoint(ops::DFG {
353 signature: signature.clone(),
354 })
355 .unwrap();
356 hugr.add_node_with_parent(
357 hugr.entrypoint(),
358 ops::Input {
359 types: signature.input,
360 },
361 );
362 hugr.add_node_with_parent(
363 hugr.entrypoint(),
364 ops::Output {
365 types: signature.output,
366 },
367 );
368 hugr
369 }
370
371 #[fixture]
375 pub(crate) fn dfg_calling_defn_decl() -> (Hugr, FuncID<true>, FuncID<false>) {
376 let mut dfb = DFGBuilder::new(Signature::new(vec![], [bool_t()])).unwrap();
377 let new_defn = {
378 let mut mb = dfb.module_root_builder();
379 let fb = mb
380 .define_function("helper_id", Signature::new_endo([bool_t()]))
381 .unwrap();
382 let [f_inp] = fb.input_wires_arr();
383 fb.finish_with_outputs([f_inp]).unwrap()
384 };
385 let new_decl = dfb
386 .module_root_builder()
387 .declare("helper2", Signature::new_endo([bool_t()]).into())
388 .unwrap();
389 let cst = dfb.add_load_value(ops::Value::true_val());
390 let [c1] = dfb
391 .call(new_defn.handle(), &[], [cst])
392 .unwrap()
393 .outputs_arr();
394 let [c2] = dfb.call(&new_decl, &[], [c1]).unwrap().outputs_arr();
395 (
396 dfb.finish_hugr_with_outputs([c2]).unwrap(),
397 *new_defn.handle(),
398 new_decl,
399 )
400 }
401}