Skip to content

feat!: [RFC] Preliminaries for linking by name #2143

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions hugr-core/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,7 @@ pub(crate) mod test {

#[fixture]
pub(crate) fn simple_funcdef_hugr() -> Hugr {
let fn_builder =
FunctionBuilder::new("test", Signature::new(vec![bool_t()], vec![bool_t()])).unwrap();
let fn_builder = FunctionBuilder::new("test", Signature::new_endo(bool_t())).unwrap();
let [i1] = fn_builder.input_wires_arr();
fn_builder.finish_hugr_with_outputs([i1]).unwrap()
}
Expand Down
40 changes: 23 additions & 17 deletions hugr-core/src/builder/build_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ pub trait Container {
}

/// Add a [`ops::FuncDefn`] node and returns a builder to define the function
/// body graph.
/// body graph. The function has an appropriate [ops::FuncDefn::link_name] for the parent
/// (`None` for most containers / with the default impl.)
///
/// # Errors
///
Expand All @@ -94,22 +95,7 @@ pub trait Container {
name: impl Into<String>,
signature: impl Into<PolyFuncType>,
) -> Result<FunctionBuilder<&mut Hugr>, BuildError> {
let signature: PolyFuncType = signature.into();
let body = signature.body().clone();
let f_node = self.add_child_node(ops::FuncDefn {
name: name.into(),
signature,
});

// Add the extensions used by the function types.
self.use_extensions(
body.used_extensions().unwrap_or_else(|e| {
panic!("Build-time signatures should have valid extensions. {e}")
}),
);

let db = DFGBuilder::create_with_io(self.hugr_mut(), f_node, body)?;
Ok(FunctionBuilder::from_dfg_builder(db))
define_function_link_name(self, name, signature, None)
}

/// Insert a HUGR as a child of the container.
Expand Down Expand Up @@ -157,6 +143,26 @@ pub trait Container {
}
}

pub(super) fn define_function_link_name<C: Container + ?Sized>(
ctr: &mut C,
name: impl Into<String>,
signature: impl Into<PolyFuncType>,
link_name: impl Into<Option<String>>,
) -> Result<FunctionBuilder<&mut Hugr>, BuildError> {
let signature = signature.into();
let body = signature.body().clone();
let f_node = ctr.add_child_node(ops::FuncDefn::new(name.into(), signature, link_name));

// Add the extensions used by the function types.
ctr.use_extensions(
body.used_extensions()
.unwrap_or_else(|e| panic!("Build-time signatures should have valid extensions. {e}")),
);

let db = DFGBuilder::create_with_io(ctr.hugr_mut(), f_node, body)?;
Ok(FunctionBuilder::from_dfg_builder(db))
}

/// Types implementing this trait can be used to build complete HUGRs
/// (with varying root node types)
pub trait HugrBuilder: Container {
Expand Down
64 changes: 40 additions & 24 deletions hugr-core/src/builder/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,20 +152,46 @@ impl<B, T> DFGWrapper<B, T> {
pub type FunctionBuilder<B> = DFGWrapper<B, BuildHandle<FuncID<true>>>;

impl FunctionBuilder<Hugr> {
/// Initialize a builder for a `FuncDefn` rooted HUGR
/// Initialize a builder for a [`FuncDefn`](ops::FuncDefn)-rooted HUGR; the function will be private.
/// (See also [Self::new_pub], [Self::new_link_name].)
///
/// # Errors
///
/// Error in adding DFG child nodes.
pub fn new(
name: impl Into<String>,
signature: impl Into<PolyFuncType>,
) -> Result<Self, BuildError> {
let signature: PolyFuncType = signature.into();
let body = signature.body().clone();
let op = ops::FuncDefn {
signature,
name: name.into(),
};
Self::new_link_name(name, signature, None)
}

/// Initialize a builder for a FuncDefn-rooted HUGR; the function will be public
/// with the same name (see also [Self::new_link_name]).
///
/// # Errors
///
/// Error in adding DFG child nodes.
pub fn new_pub(
name: impl Into<String>,
signature: impl Into<PolyFuncType>,
) -> Result<Self, BuildError> {
let name = name.into();
Self::new_link_name(name.clone(), signature, Some(name))
}

/// Initialize a builder for a FuncDefn-rooted HUGR, with the specified
/// [link_name](ops::FuncDefn::link_name).
///
/// # Errors
///
/// Error in adding DFG child nodes.
pub fn new_link_name(
name: impl Into<String>,
signature: impl Into<PolyFuncType>,
link_name: impl Into<Option<String>>,
) -> Result<Self, BuildError> {
let op = ops::FuncDefn::new(name.into(), signature.into(), link_name);
let body = op.signature.body().clone();

let base = Hugr::new_with_entrypoint(op).expect("FuncDefn entrypoint should be valid");
let root = base.entrypoint();
Expand Down Expand Up @@ -253,22 +279,12 @@ impl FunctionBuilder<Hugr> {
/// Returns a reference to the new optype.
fn update_fn_signature(&mut self, f: impl FnOnce(Signature) -> Signature) -> &ops::FuncDefn {
let parent = self.container_node();
let old_optype = self
.hugr()
.get_optype(parent)
.as_func_defn()
.expect("FunctionBuilder node must be a FuncDefn");
let signature = old_optype.inner_signature().into_owned();
let name = old_optype.name.clone();
self.hugr_mut().replace_op(
parent,
ops::FuncDefn {
signature: f(signature).into(),
name,
},
);

self.hugr().get_optype(parent).as_func_defn().unwrap()
let ops::OpType::FuncDefn(fd) = self.hugr_mut().optype_mut(parent) else {
panic!("FunctionBuilder node must be a FuncDefn")
};
fd.signature = f(fd.inner_signature().into_owned()).into();
&*fd
}
}

Expand Down Expand Up @@ -531,8 +547,8 @@ pub(crate) mod test {
let mut module_builder = ModuleBuilder::new();

let (dfg_node, f_node) = {
let mut f_build = module_builder
.define_function("main", Signature::new(vec![bool_t()], vec![bool_t()]))?;
let mut f_build =
module_builder.define_function("main", Signature::new_endo(bool_t()))?;

let [i1] = f_build.input_wires_arr();
let dfg = f_build.add_hugr_with_wires(dfg_hugr, [i1])?;
Expand Down
61 changes: 44 additions & 17 deletions hugr-core/src/builder/module.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use super::{
BuildError, Container,
build_traits::HugrBuilder,
build_traits::{HugrBuilder, define_function_link_name},
dataflow::{DFGBuilder, FunctionBuilder},
};

use crate::hugr::ValidationError;
use crate::hugr::internal::HugrMutInternals;
use crate::hugr::views::HugrView;
use crate::ops;
use crate::types::{PolyFuncType, Type, TypeBound};

use crate::ops::handle::{AliasID, FuncID, NodeHandle};
use crate::types::{PolyFuncType, Type, TypeBound};

use crate::{Hugr, Node};
use smol_str::SmolStr;
Expand All @@ -33,6 +32,23 @@ impl<T: AsMut<Hugr> + AsRef<Hugr>> Container for ModuleBuilder<T> {
fn hugr(&self) -> &Hugr {
self.0.as_ref()
}

/// Override the default to make the function public, with [link_name](ops::FuncDefn::link_name)
/// the same as `name`. (See also [Self::define_function_link_name].)
/// Returns a builder to define the function body graph.
///
/// # Errors
///
/// This function will return an error if there is an error in adding the
/// [`ops::FuncDefn`] node.
fn define_function(
&mut self,
name: impl Into<String>,
signature: impl Into<PolyFuncType>,
) -> Result<FunctionBuilder<&mut Hugr>, BuildError> {
let name = name.into();
define_function_link_name(self, name.clone(), signature, Some(name))
}
}

impl ModuleBuilder<Hugr> {
Expand All @@ -57,7 +73,7 @@ impl HugrBuilder for ModuleBuilder<Hugr> {
}

impl<T: AsMut<Hugr> + AsRef<Hugr>> ModuleBuilder<T> {
/// Replace a [`ops::FuncDecl`] with [`ops::FuncDefn`] and return a builder for
/// Replace a [`ops::FuncDecl`] with public [`ops::FuncDefn`] and return a builder for
/// the defining graph.
///
/// # Errors
Expand All @@ -69,23 +85,37 @@ impl<T: AsMut<Hugr> + AsRef<Hugr>> ModuleBuilder<T> {
f_id: &FuncID<false>,
) -> Result<FunctionBuilder<&mut Hugr>, BuildError> {
let f_node = f_id.node();
let ops::FuncDecl { signature, name } = self
.hugr()
.get_optype(f_node)
.as_func_decl()
.ok_or(BuildError::UnexpectedType {
let opty = self.hugr_mut().optype_mut(f_node);
let ops::OpType::FuncDecl(ops::FuncDecl { signature, name }) = opty else {
return Err(BuildError::UnexpectedType {
node: f_node,
op_desc: "crate::ops::OpType::FuncDecl",
})?
.clone();
});
};

let body = signature.body().clone();
self.hugr_mut()
.replace_op(f_node, ops::FuncDefn { name, signature });
*opty = ops::FuncDefn::new_public(name, signature.clone()).into();

let db = DFGBuilder::create_with_io(self.hugr_mut(), f_node, body)?;
Ok(FunctionBuilder::from_dfg_builder(db))
}

/// Add a [`ops::FuncDefn`] node, with both `name` and `link_name` explicitly specified.
/// Returns a builder to define the function body graph.
///
/// # Errors
///
/// This function will return an error if there is an error in adding the
/// [`ops::FuncDefn`] node.
pub fn define_function_link_name(
&mut self,
name: impl Into<String>,
signature: impl Into<PolyFuncType>,
link_name: impl Into<Option<String>>,
) -> Result<FunctionBuilder<&mut Hugr>, BuildError> {
define_function_link_name(self, name, signature, link_name)
}

/// Declare a function with `signature` and return a handle to the declaration.
///
/// # Errors
Expand Down Expand Up @@ -199,10 +229,7 @@ mod test {

let f_build = module_builder.define_function(
"main",
Signature::new(
vec![qubit_state_type.get_alias_type()],
vec![qubit_state_type.get_alias_type()],
),
Signature::new_endo(qubit_state_type.get_alias_type()),
)?;
n_identity(f_build)?;
module_builder.finish_hugr()
Expand Down
9 changes: 2 additions & 7 deletions hugr-core/src/hugr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,13 +443,8 @@ fn make_module_hugr(root_op: OpType, nodes: usize, ports: usize) -> Option<Hugr>
let dataflow_inputs = signature.input_count();
let dataflow_outputs = signature.output_count();

let func = hugr.add_node_with_parent(
module,
ops::FuncDefn {
name: "main".into(),
signature: signature.clone().into(),
},
);
let func =
hugr.add_node_with_parent(module, ops::FuncDefn::new_public("main", signature.clone()));
let inp = hugr.add_node_with_parent(
func,
ops::Input {
Expand Down
13 changes: 5 additions & 8 deletions hugr-core/src/hugr/hugrmut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,10 +630,10 @@ mod test {
// Start a main function with two nat inputs.
let f: Node = hugr.add_node_with_parent(
module,
ops::FuncDefn {
name: "main".into(),
signature: Signature::new(vec![usize_t()], vec![usize_t(), usize_t()]).into(),
},
ops::FuncDefn::new_public(
"main",
Signature::new(usize_t(), vec![usize_t(), usize_t()]),
),
);

{
Expand Down Expand Up @@ -678,10 +678,7 @@ mod test {
let [foo, bar] = ["foo", "bar"].map(|name| {
let fd = hugr.add_node_with_parent(
root,
FuncDefn {
name: name.to_string(),
signature: Signature::new_endo(usize_t()).into(),
},
FuncDefn::new_private(name, Signature::new_endo(usize_t())),
);
let inp = hugr.add_node_with_parent(fd, Input::new(usize_t()));
let out = hugr.add_node_with_parent(fd, Output::new(usize_t()));
Expand Down
3 changes: 2 additions & 1 deletion hugr-core/src/hugr/serialize/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,8 @@ fn roundtrip_polyfunctype_varlen(#[case] poly_func_type: PolyFuncTypeRV) {

#[rstest]
#[case(ops::Module::new())]
#[case(ops::FuncDefn { name: "polyfunc1".into(), signature: polyfunctype1()})]
#[case(ops::FuncDefn::new("polyfunc1", polyfunctype1(), "pf1".to_string()))]
#[case(ops::FuncDefn { name: "polyfunc1".into(), signature: polyfunctype1(), link_name: None})]
#[case(ops::FuncDecl { name: "polyfunc2".into(), signature: polyfunctype1()})]
#[case(ops::AliasDefn { name: "aliasdefn".into(), definition: Type::new_unit_sum(4)})]
#[case(ops::AliasDecl { name: "aliasdecl".into(), bound: TypeBound::Any})]
Expand Down
Loading
Loading