From 9b47f62383684b013b25088b1fb97e649304a7ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agust=C3=ADn=20Borgna?= Date: Tue, 15 Oct 2024 15:32:07 +0100 Subject: [PATCH 1/3] feat: Render function names in `mermaid`/`dot` --- hugr-core/src/builder.rs | 8 ++++++++ hugr-core/src/hugr/views/render.rs | 14 +++++++++++--- .../hugr_core__hugr__views__tests__dot_func.snap | 15 +++++++++++++++ .../hugr_core__hugr__views__tests__mmd_func.snap | 11 +++++++++++ hugr-core/src/hugr/views/tests.rs | 2 ++ 5 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__dot_func.snap create mode 100644 hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__mmd_func.snap diff --git a/hugr-core/src/builder.rs b/hugr-core/src/builder.rs index 196b1ab6a..90dc7c154 100644 --- a/hugr-core/src/builder.rs +++ b/hugr-core/src/builder.rs @@ -282,6 +282,14 @@ pub(crate) mod test { dfg_builder.finish_prelude_hugr_with_outputs([i1]).unwrap() } + #[fixture] + pub(crate) fn simple_funcdef_hugr() -> Hugr { + let fn_builder = + FunctionBuilder::new("test", Signature::new(type_row![BIT], type_row![BIT])).unwrap(); + let [i1] = fn_builder.input_wires_arr(); + fn_builder.finish_prelude_hugr_with_outputs([i1]).unwrap() + } + #[fixture] pub(crate) fn simple_cfg_hugr() -> Hugr { let mut cfg_builder = diff --git a/hugr-core/src/hugr/views/render.rs b/hugr-core/src/hugr/views/render.rs index 5d6bf2ade..caa4770a2 100644 --- a/hugr-core/src/hugr/views/render.rs +++ b/hugr-core/src/hugr/views/render.rs @@ -4,7 +4,7 @@ use portgraph::render::{EdgeStyle, NodeStyle, PortStyle}; use portgraph::{LinkView, NodeIndex, PortIndex, PortView}; -use crate::ops::NamedOp; +use crate::ops::{NamedOp, OpType}; use crate::types::EdgeKind; use crate::HugrView; @@ -35,16 +35,24 @@ pub(super) fn node_style( h: &H, config: RenderConfig, ) -> Box NodeStyle + '_> { + fn node_name(h: &H, n: NodeIndex) -> String { + match h.get_optype(n.into()) { + OpType::FuncDecl(f) => format!("FuncDecl: \"{}\"", f.name), + OpType::FuncDefn(f) => format!("FuncDefn: \"{}\"", f.name), + op => op.name().to_string(), + } + } + if config.node_indices { Box::new(move |n| { NodeStyle::Box(format!( "({ni}) {name}", ni = n.index(), - name = h.get_optype(n.into()).name() + name = node_name(h, n) )) }) } else { - Box::new(move |n| NodeStyle::Box(h.get_optype(n.into()).name().to_string())) + Box::new(move |n| NodeStyle::Box(node_name(h, n))) } } diff --git a/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__dot_func.snap b/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__dot_func.snap new file mode 100644 index 000000000..9cb4b7ee4 --- /dev/null +++ b/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__dot_func.snap @@ -0,0 +1,15 @@ +--- +source: hugr-core/src/hugr/views/tests.rs +expression: h.dot_string() +--- +digraph { +0 [shape=plain label=<
(0) FuncDefn: "test"
>] +1 [shape=plain label=<
(1) Input
0: []+[]
>] +1:out0 -> 2:in0 [style=""] +2 [shape=plain label=<
0: []+[]
(2) Output
>] +hier0 [shape=plain label="0"] +hier0 -> hier1 [style = "dashed"] +hier0 -> hier2 [style = "dashed"] +hier1 [shape=plain label="1"] +hier2 [shape=plain label="2"] +} diff --git a/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__mmd_func.snap b/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__mmd_func.snap new file mode 100644 index 000000000..45bf1a427 --- /dev/null +++ b/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__mmd_func.snap @@ -0,0 +1,11 @@ +--- +source: hugr-core/src/hugr/views/tests.rs +expression: h.mermaid_string() +--- +graph LR + subgraph 0 ["(0) FuncDefn: #quot;test#quot;"] + direction LR + 1["(1) Input"] + 2["(2) Output"] + 1--"0:0
[]+[]"-->2 + end diff --git a/hugr-core/src/hugr/views/tests.rs b/hugr-core/src/hugr/views/tests.rs index 04004decd..fb5ef48fa 100644 --- a/hugr-core/src/hugr/views/tests.rs +++ b/hugr-core/src/hugr/views/tests.rs @@ -71,6 +71,7 @@ fn node_connections( #[case::dfg("dot_dfg", sample_hugr().0)] #[case::cfg("dot_cfg", crate::builder::test::simple_cfg_hugr())] #[case::empty_dfg("dot_empty_dfg", crate::builder::test::simple_dfg_hugr())] +#[case::func("dot_func", crate::builder::test::simple_funcdef_hugr())] #[cfg_attr(miri, ignore)] // Opening files is not supported in (isolated) miri fn dot_string(#[case] test_name: &str, #[case] h: Hugr) { insta::assert_snapshot!(test_name, h.dot_string()); @@ -84,6 +85,7 @@ fn dot_string(#[case] test_name: &str, #[case] h: Hugr) { #[case::dfg("mmd_dfg", sample_hugr().0)] #[case::cfg("mmd_cfg", crate::builder::test::simple_cfg_hugr())] #[case::empty_dfg("mmd_empty_dfg", crate::builder::test::simple_dfg_hugr())] +#[case::func("mmd_func", crate::builder::test::simple_funcdef_hugr())] #[cfg_attr(miri, ignore)] // Opening files is not supported in (isolated) miri fn mermaid_string(#[case] test_name: &str, #[case] h: Hugr) { insta::assert_snapshot!(test_name, h.mermaid_string()); From 1b4afffcc314bfe6b19a76d406b3c4a88dbbab02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agust=C3=ADn=20Borgna?= Date: Wed, 16 Oct 2024 17:38:54 +0100 Subject: [PATCH 2/3] More tests --- hugr-core/src/builder.rs | 8 ++++++++ .../hugr_core__hugr__views__tests__dot_module.snap | 11 +++++++++++ .../hugr_core__hugr__views__tests__mmd_module.snap | 9 +++++++++ hugr-core/src/hugr/views/tests.rs | 2 ++ 4 files changed, 30 insertions(+) create mode 100644 hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__dot_module.snap create mode 100644 hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__mmd_module.snap diff --git a/hugr-core/src/builder.rs b/hugr-core/src/builder.rs index 90dc7c154..f955477fd 100644 --- a/hugr-core/src/builder.rs +++ b/hugr-core/src/builder.rs @@ -290,6 +290,14 @@ pub(crate) mod test { fn_builder.finish_prelude_hugr_with_outputs([i1]).unwrap() } + #[fixture] + pub(crate) fn simple_module_hugr() -> Hugr { + let mut builder = ModuleBuilder::new(); + let sig = Signature::new(type_row![BIT], type_row![BIT]); + builder.declare("test", sig.into()).unwrap(); + builder.finish_prelude_hugr().unwrap() + } + #[fixture] pub(crate) fn simple_cfg_hugr() -> Hugr { let mut cfg_builder = diff --git a/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__dot_module.snap b/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__dot_module.snap new file mode 100644 index 000000000..42fede6b6 --- /dev/null +++ b/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__dot_module.snap @@ -0,0 +1,11 @@ +--- +source: hugr-core/src/hugr/views/tests.rs +expression: h.dot_string() +--- +digraph { +0 [shape=plain label=<
(0) Module
>] +1 [shape=plain label=<
(1) FuncDecl: "test"
0: forall params.iter().map(ToString::to_string).join(" "). body
>] +hier0 [shape=plain label="0"] +hier0 -> hier1 [style = "dashed"] +hier1 [shape=plain label="1"] +} diff --git a/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__mmd_module.snap b/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__mmd_module.snap new file mode 100644 index 000000000..0bb2de60e --- /dev/null +++ b/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__mmd_module.snap @@ -0,0 +1,9 @@ +--- +source: hugr-core/src/hugr/views/tests.rs +expression: h.mermaid_string() +--- +graph LR + subgraph 0 ["(0) Module"] + direction LR + 1["(1) FuncDecl: #quot;test#quot;"] + end diff --git a/hugr-core/src/hugr/views/tests.rs b/hugr-core/src/hugr/views/tests.rs index fb5ef48fa..c52957b2c 100644 --- a/hugr-core/src/hugr/views/tests.rs +++ b/hugr-core/src/hugr/views/tests.rs @@ -72,6 +72,7 @@ fn node_connections( #[case::cfg("dot_cfg", crate::builder::test::simple_cfg_hugr())] #[case::empty_dfg("dot_empty_dfg", crate::builder::test::simple_dfg_hugr())] #[case::func("dot_func", crate::builder::test::simple_funcdef_hugr())] +#[case::module("dot_module", crate::builder::test::simple_module_hugr())] #[cfg_attr(miri, ignore)] // Opening files is not supported in (isolated) miri fn dot_string(#[case] test_name: &str, #[case] h: Hugr) { insta::assert_snapshot!(test_name, h.dot_string()); @@ -86,6 +87,7 @@ fn dot_string(#[case] test_name: &str, #[case] h: Hugr) { #[case::cfg("mmd_cfg", crate::builder::test::simple_cfg_hugr())] #[case::empty_dfg("mmd_empty_dfg", crate::builder::test::simple_dfg_hugr())] #[case::func("mmd_func", crate::builder::test::simple_funcdef_hugr())] +#[case::module("mmd_module", crate::builder::test::simple_module_hugr())] #[cfg_attr(miri, ignore)] // Opening files is not supported in (isolated) miri fn mermaid_string(#[case] test_name: &str, #[case] h: Hugr) { insta::assert_snapshot!(test_name, h.mermaid_string()); From 6204324ac5f24354eddebcf691a527babdcbc4cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agust=C3=ADn=20Borgna?= Date: Thu, 17 Oct 2024 15:04:07 +0100 Subject: [PATCH 3/3] Fix poly_func display impl --- ...gr_core__hugr__views__tests__dot_func.snap | 2 +- ..._core__hugr__views__tests__dot_module.snap | 2 +- hugr-core/src/types/poly_func.rs | 19 ++++++++++++++----- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__dot_func.snap b/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__dot_func.snap index 9cb4b7ee4..e1bbeae4e 100644 --- a/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__dot_func.snap +++ b/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__dot_func.snap @@ -3,7 +3,7 @@ source: hugr-core/src/hugr/views/tests.rs expression: h.dot_string() --- digraph { -0 [shape=plain label=<
(0) FuncDefn: "test"
>] +0 [shape=plain label=<
(0) FuncDefn: "test"
0: [[]+[]] -> [[]][[]+[]]
>] 1 [shape=plain label=<
(1) Input
0: []+[]
>] 1:out0 -> 2:in0 [style=""] 2 [shape=plain label=<
0: []+[]
(2) Output
>] diff --git a/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__dot_module.snap b/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__dot_module.snap index 42fede6b6..37691fa9c 100644 --- a/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__dot_module.snap +++ b/hugr-core/src/hugr/views/snapshots/hugr_core__hugr__views__tests__dot_module.snap @@ -4,7 +4,7 @@ expression: h.dot_string() --- digraph { 0 [shape=plain label=<
(0) Module
>] -1 [shape=plain label=<
(1) FuncDecl: "test"
0: forall params.iter().map(ToString::to_string).join(" "). body
>] +1 [shape=plain label=<
(1) FuncDecl: "test"
0: [[]+[]] -> [[]][[]+[]]
>] hier0 [shape=plain label="0"] hier0 -> hier1 [style = "dashed"] hier1 [shape=plain label="1"] diff --git a/hugr-core/src/types/poly_func.rs b/hugr-core/src/types/poly_func.rs index 837a4e22d..b168556bf 100644 --- a/hugr-core/src/types/poly_func.rs +++ b/hugr-core/src/types/poly_func.rs @@ -1,5 +1,7 @@ //! Polymorphic Function Types +use itertools::Itertools; + use crate::extension::{ExtensionRegistry, SignatureError}; #[cfg(test)] use { @@ -22,11 +24,7 @@ use super::{signature::FuncTypeBase, MaybeRV, NoRV, RowVariable}; Clone, PartialEq, Debug, Eq, Hash, derive_more::Display, serde::Serialize, serde::Deserialize, )] #[cfg_attr(test, derive(Arbitrary), proptest(params = "RecursionDepth"))] -#[display( - "forall {}. {}", - "params.iter().map(ToString::to_string).join(\" \")", - "body" -)] +#[display("{}{body}", self.display_params())] pub struct PolyFuncTypeBase { /// The declared type parameters, i.e., these must be instantiated with /// the same number of [TypeArg]s before the function can be called. This @@ -136,6 +134,17 @@ impl PolyFuncTypeBase { // TODO https://github.com/CQCL/hugr/issues/624 validate TypeParams declared here, too self.body.validate(reg, &self.params) } + + /// Helper function for the Display implementation + fn display_params(&self) -> String { + if self.params.is_empty() { + return String::new(); + } + format!( + "forall {}. ", + self.params.iter().map(ToString::to_string).join(" ") + ) + } } #[cfg(test)]