use thiserror::Error;
use crate::extension::SignatureError;
use crate::extension::simple_op::OpLoadError;
use crate::hugr::ValidationError;
use crate::hugr::linking::{NameLinkingError, NodeLinkingError};
use crate::ops::handle::{BasicBlockID, CfgID, ConditionalID, DfgID, FuncID, TailLoopID};
use crate::ops::{NamedOp, OpType};
use crate::types::Type;
use crate::types::{ConstTypeError, Signature, TypeRow};
use crate::{Node, Port, Wire};
pub mod handle;
pub use handle::BuildHandle;
mod build_traits;
pub use build_traits::{
Container, Dataflow, DataflowHugr, DataflowSubContainer, HugrBuilder, SubContainer,
};
pub mod dataflow;
pub use dataflow::{DFGBuilder, DFGWrapper, FunctionBuilder};
mod module;
pub use module::ModuleBuilder;
mod cfg;
pub use cfg::{BlockBuilder, CFGBuilder};
mod tail_loop;
pub use tail_loop::TailLoopBuilder;
mod conditional;
pub use conditional::{CaseBuilder, ConditionalBuilder};
mod circuit;
pub use circuit::{CircuitBuildError, CircuitBuilder};
pub fn endo_sig(types: impl Into<TypeRow>) -> Signature {
Signature::new_endo(types)
}
pub fn inout_sig(inputs: impl Into<TypeRow>, outputs: impl Into<TypeRow>) -> Signature {
Signature::new(inputs, outputs)
}
#[derive(Debug, Clone, PartialEq, Error)]
#[non_exhaustive]
pub enum BuildError {
#[error("The constructed HUGR is invalid: {0}.")]
InvalidHUGR(#[from] ValidationError<Node>),
#[error(transparent)]
SignatureError(#[from] SignatureError),
#[error("Constant failed typechecking: {0}")]
BadConstant(#[from] ConstTypeError),
#[error("CFG entry node already built for CFG node: {0}.")]
EntryBuiltError(Node),
#[error(
"Cannot initialize hugr for a BasicBlockBuilder with complex sum-rows. Use a CFGBuilder instead."
)]
BasicBlockTooComplex,
#[error("Node with index {node} does not have type {op_desc} as expected.")]
UnexpectedType {
node: Node,
op_desc: &'static str,
},
#[error("Error building Conditional node: {0}.")]
ConditionalError(#[from] conditional::ConditionalBuildError),
#[error("{node} not found in the Hugr")]
NodeNotFound {
node: Node,
},
#[error("In inserting Hugr: {0}")]
HugrNodeLinkingError(#[from] NodeLinkingError<Node, Node>),
#[error{"In linking Hugr: {0}"}]
HugrLinkingError(#[from] NameLinkingError<Node, Node>),
#[error("In inserting HugrView: {0}")]
HugrViewInsertionError(String),
#[error("Wire not found in Hugr: {0}.")]
WireNotFound(Wire),
#[error("Error in CircuitBuilder: {0}.")]
CircuitError(#[from] circuit::CircuitBuildError),
#[error("Found an error while setting the outputs of a {} container, {container_node}. {error}", .container_op.name())]
#[allow(missing_docs)]
OutputWiring {
container_op: Box<OpType>,
container_node: Node,
#[source]
error: BuilderWiringError,
},
#[error("Got an input wire while adding a {} to the circuit. {error}", .op.name())]
#[allow(missing_docs)]
OperationWiring {
op: Box<OpType>,
#[source]
error: BuilderWiringError,
},
#[error("Failed to load an extension op: {0}")]
#[allow(missing_docs)]
ExtensionOp(#[from] OpLoadError),
}
#[derive(Debug, Clone, PartialEq, Error)]
#[non_exhaustive]
pub enum BuilderWiringError {
#[error("Cannot copy linear type {typ} from output {src_offset} of node {src}")]
#[allow(missing_docs)]
NoCopyLinear {
typ: Box<Type>,
src: Node,
src_offset: Port,
},
#[error(
"Cannot connect an inter-graph edge between unrelated nodes. Tried connecting {src} ({src_offset}) with {dst} ({dst_offset})."
)]
#[allow(missing_docs)]
NoRelationIntergraph {
src: Node,
src_offset: Port,
dst: Node,
dst_offset: Port,
},
#[error(
"Inter-graph edges cannot carry non-copyable data {typ}. Tried connecting {src} ({src_offset}) with {dst} ({dst_offset})."
)]
#[allow(missing_docs)]
NonCopyableIntergraph {
src: Node,
src_offset: Port,
dst: Node,
dst_offset: Port,
typ: Box<Type>,
},
}
#[cfg(test)]
pub(crate) mod test {
use rstest::fixture;
use crate::Hugr;
use crate::extension::prelude::{bool_t, usize_t};
use crate::hugr::{HugrMut, views::HugrView};
use crate::ops;
use crate::package::Package;
use crate::types::{PolyFuncType, Signature};
use super::handle::BuildHandle;
use super::{
BuildError, CFGBuilder, DFGBuilder, Dataflow, DataflowHugr, FuncID, FunctionBuilder,
ModuleBuilder,
};
use super::{DataflowSubContainer, HugrBuilder};
pub(crate) fn n_identity<T: DataflowSubContainer>(
dataflow_builder: T,
) -> Result<T::ContainerHandle, BuildError> {
let w = dataflow_builder.input_wires();
dataflow_builder.finish_with_outputs(w)
}
pub(crate) fn build_main(
signature: PolyFuncType,
f: impl FnOnce(FunctionBuilder<&mut Hugr>) -> Result<BuildHandle<FuncID<true>>, BuildError>,
) -> Result<Hugr, BuildError> {
let mut module_builder = ModuleBuilder::new();
let f_builder = module_builder.define_function("main", signature)?;
f(f_builder)?;
Ok(module_builder.finish_hugr()?)
}
#[fixture]
pub(crate) fn simple_dfg_hugr() -> Hugr {
let dfg_builder = DFGBuilder::new(Signature::new(vec![bool_t()], vec![bool_t()])).unwrap();
let [i1] = dfg_builder.input_wires_arr();
dfg_builder.finish_hugr_with_outputs([i1]).unwrap()
}
#[fixture]
pub(crate) fn simple_funcdef_hugr() -> Hugr {
let fn_builder =
FunctionBuilder::new("test", Signature::new(vec![bool_t()], vec![bool_t()])).unwrap();
let [i1] = fn_builder.input_wires_arr();
fn_builder.finish_hugr_with_outputs([i1]).unwrap()
}
#[fixture]
pub(crate) fn simple_module_hugr() -> Hugr {
let mut builder = ModuleBuilder::new();
let sig = Signature::new(vec![bool_t()], vec![bool_t()]);
builder.declare("test", sig.into()).unwrap();
builder.finish_hugr().unwrap()
}
#[fixture]
pub(crate) fn simple_cfg_hugr() -> Hugr {
let mut cfg_builder =
CFGBuilder::new(Signature::new(vec![usize_t()], vec![usize_t()])).unwrap();
super::cfg::test::build_basic_cfg(&mut cfg_builder).unwrap();
cfg_builder.finish_hugr().unwrap()
}
#[fixture]
pub(crate) fn simple_package() -> Package {
let hugr = simple_module_hugr();
Package::new([hugr])
}
#[fixture]
pub(crate) fn multi_module_package() -> Package {
let hugr0 = simple_module_hugr();
let hugr1 = simple_module_hugr();
Package::new([hugr0, hugr1])
}
pub(crate) fn closed_dfg_root_hugr(signature: Signature) -> Hugr {
let mut hugr = Hugr::new_with_entrypoint(ops::DFG {
signature: signature.clone(),
})
.unwrap();
hugr.add_node_with_parent(
hugr.entrypoint(),
ops::Input {
types: signature.input,
},
);
hugr.add_node_with_parent(
hugr.entrypoint(),
ops::Output {
types: signature.output,
},
);
hugr
}
#[fixture]
pub(crate) fn dfg_calling_defn_decl() -> (Hugr, FuncID<true>, FuncID<false>) {
let mut dfb = DFGBuilder::new(Signature::new(vec![], [bool_t()])).unwrap();
let new_defn = {
let mut mb = dfb.module_root_builder();
let fb = mb
.define_function("helper_id", Signature::new_endo([bool_t()]))
.unwrap();
let [f_inp] = fb.input_wires_arr();
fb.finish_with_outputs([f_inp]).unwrap()
};
let new_decl = dfb
.module_root_builder()
.declare("helper2", Signature::new_endo([bool_t()]).into())
.unwrap();
let cst = dfb.add_load_value(ops::Value::true_val());
let [c1] = dfb
.call(new_defn.handle(), &[], [cst])
.unwrap()
.outputs_arr();
let [c2] = dfb.call(&new_decl, &[], [c1]).unwrap().outputs_arr();
(
dfb.finish_hugr_with_outputs([c2]).unwrap(),
*new_defn.handle(),
new_decl,
)
}
}