From 12c4b6e6a7e0fcc23cc95fcf148fba4196643b6e Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 31 Mar 2025 20:06:04 +0100 Subject: [PATCH 01/11] No need for ConstFoldContext to impl Deref --- hugr-passes/src/const_fold.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/hugr-passes/src/const_fold.rs b/hugr-passes/src/const_fold.rs index 7552ed36f..1dc4554cf 100644 --- a/hugr-passes/src/const_fold.rs +++ b/hugr-passes/src/const_fold.rs @@ -207,13 +207,6 @@ pub fn constant_fold_pass(h: &mut H) { struct ConstFoldContext<'a, H>(&'a H); -impl std::ops::Deref for ConstFoldContext<'_, H> { - type Target = H; - fn deref(&self) -> &H { - self.0 - } -} - impl> ConstLoader> for ConstFoldContext<'_, H> { type Node = H::Node; @@ -244,7 +237,7 @@ impl> ConstLoader> for ConstFoldCo }; // Returning the function body as a value, here, would be sufficient for inlining IndirectCall // but not for transforming to a direct Call. - let func = DescendantsGraph::>::try_new(&**self, node).ok()?; + let func = DescendantsGraph::>::try_new(self.0, node).ok()?; Some(ValueHandle::new_const_hugr( ConstLocation::Node(node), Box::new(func.extract_hugr()), From 3f764ecce865339f444024f8b3b209fa8365b077 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 31 Mar 2025 20:06:34 +0100 Subject: [PATCH 02/11] Hide value_handle, no need for it to be public --- hugr-passes/src/const_fold.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hugr-passes/src/const_fold.rs b/hugr-passes/src/const_fold.rs index 1dc4554cf..d0ec483ac 100644 --- a/hugr-passes/src/const_fold.rs +++ b/hugr-passes/src/const_fold.rs @@ -2,7 +2,7 @@ //! Constant-folding pass. //! An (example) use of the [dataflow analysis framework](super::dataflow). -pub mod value_handle; +mod value_handle; use std::{collections::HashMap, sync::Arc}; use thiserror::Error; From f6fbf08bf02d3973d413a8e2def1d25ed64e7198 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 31 Mar 2025 20:24:25 +0100 Subject: [PATCH 03/11] Add ValueHandle::NodeRef(N, TypeArgs), with fallible conversion to Value --- hugr-passes/src/const_fold/value_handle.rs | 25 ++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/hugr-passes/src/const_fold/value_handle.rs b/hugr-passes/src/const_fold/value_handle.rs index bda7bffd2..441b88788 100644 --- a/hugr-passes/src/const_fold/value_handle.rs +++ b/hugr-passes/src/const_fold/value_handle.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use hugr_core::core::HugrNode; use hugr_core::ops::constant::OpaqueValue; use hugr_core::ops::Value; +use hugr_core::types::TypeArg; use hugr_core::{Hugr, Node}; use itertools::Either; @@ -46,6 +47,15 @@ impl Hash for HashedConst { /// An [Eq]-able and [Hash]-able leaf (non-[Sum](Value::Sum)) Value #[derive(Clone, Debug)] pub enum ValueHandle { + /// The result of [LoadFunction] on a [FuncDefn] (or [FuncDecl]), i.e. a "function + /// pointer" to a function in the Hugr. (Cannot be represented as a [Value::Function] + /// without lots of cloning, because it may have static edges from other + /// functions/constants/etc.) + /// + /// [LoadFunction]: hugr_core::ops::LoadFunction + /// [FuncDefn]: hugr_core::ops::FuncDefn + /// [FuncDecl]: hugr_core::ops::FuncDefn + NodeRef(N, Vec), /// A [Value::Extension] that has been hashed Hashable(HashedConst), /// Either a [Value::Extension] that can't be hashed, or a [Value::Function]. @@ -108,6 +118,7 @@ impl AbstractValue for ValueHandle {} impl PartialEq for ValueHandle { fn eq(&self, other: &Self) -> bool { match (self, other) { + (Self::NodeRef(n1, args1), Self::NodeRef(n2, args2)) => n1 == n2 && args1 == args2, (Self::Hashable(h1), Self::Hashable(h2)) => h1 == h2, ( Self::Unhashable { @@ -138,6 +149,10 @@ impl Eq for ValueHandle {} impl Hash for ValueHandle { fn hash(&self, state: &mut I) { match self { + ValueHandle::NodeRef(n, args) => { + n.hash(state); + args.hash(state); + } ValueHandle::Hashable(hc) => hc.hash(state), ValueHandle::Unhashable { node, @@ -153,9 +168,11 @@ impl Hash for ValueHandle { // Unfortunately we need From for Value to be able to pass // Value's into interpret_leaf_op. So that probably doesn't make sense... -impl From> for Value { - fn from(value: ValueHandle) -> Self { - match value { +impl TryFrom> for Value { + type Error = N; + fn try_from(value: ValueHandle) -> Result { + Ok(match value { + ValueHandle::NodeRef(n, _) => return Err(n), ValueHandle::Hashable(HashedConst { val, .. }) | ValueHandle::Unhashable { leaf: Either::Left(val), @@ -169,7 +186,7 @@ impl From> for Value { } => Value::function(Arc::try_unwrap(hugr).unwrap_or_else(|a| a.as_ref().clone())) .map_err(|e| e.to_string()) .unwrap(), - } + }) } } From 817b9d9e52d75f3667c343be696f2f9f92c6d564 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 31 Mar 2025 20:33:45 +0100 Subject: [PATCH 04/11] ConstFoldContext handles LoadFunction by returning ValueHandle::NodeRef --- hugr-passes/src/const_fold.rs | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/hugr-passes/src/const_fold.rs b/hugr-passes/src/const_fold.rs index d0ec483ac..82803cf4d 100644 --- a/hugr-passes/src/const_fold.rs +++ b/hugr-passes/src/const_fold.rs @@ -7,13 +7,9 @@ use std::{collections::HashMap, sync::Arc}; use thiserror::Error; use hugr_core::{ - hugr::{ - hugrmut::HugrMut, - views::{DescendantsGraph, ExtractHugr, HierarchyView}, - }, + hugr::hugrmut::HugrMut, ops::{ - constant::OpaqueValue, handle::FuncID, Const, DataflowOpTrait, ExtensionOp, LoadConstant, - OpType, Value, + constant::OpaqueValue, Const, DataflowOpTrait, ExtensionOp, LoadConstant, OpType, Value, }, types::{EdgeKind, TypeArg}, HugrView, IncomingPort, Node, NodeIndex, OutgoingPort, PortIndex, Wire, @@ -231,17 +227,7 @@ impl> ConstLoader> for ConstFoldCo node: H::Node, type_args: &[TypeArg], ) -> Option> { - if !type_args.is_empty() { - // TODO: substitution across Hugr (https://github.com/CQCL/hugr/issues/709) - return None; - }; - // Returning the function body as a value, here, would be sufficient for inlining IndirectCall - // but not for transforming to a direct Call. - let func = DescendantsGraph::>::try_new(self.0, node).ok()?; - Some(ValueHandle::new_const_hugr( - ConstLocation::Node(node), - Box::new(func.extract_hugr()), - )) + Some(ValueHandle::NodeRef(node, type_args.to_vec())) } } From 2676af78ac9a24e4d14f364b9e4c7443d210828f Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 31 Mar 2025 20:48:57 +0100 Subject: [PATCH 05/11] DFContext interpret_call_indirect --- hugr-passes/src/dataflow.rs | 12 ++++++++++++ hugr-passes/src/dataflow/datalog.rs | 9 ++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/hugr-passes/src/dataflow.rs b/hugr-passes/src/dataflow.rs index 43caa9c94..6db55b92b 100644 --- a/hugr-passes/src/dataflow.rs +++ b/hugr-passes/src/dataflow.rs @@ -35,6 +35,18 @@ pub trait DFContext: ConstLoader { _outs: &mut [PartialValue], ) { } + + /// Given lattice values for the called function, and arguments to pass to it, update + /// lattice values for the (dataflow) outputs + /// of a [CallIndirect](hugr_core::ops::CallIndirect). + /// (The default does nothing, i.e. leaves `Top` for all outputs.) + fn interpret_call_indirect( + &mut self, + _func: &PartialValue, + _args: &[PartialValue], + _outs: &mut [PartialValue], + ) { + } } /// A location where a [Value] could be find in a Hugr. That is, diff --git a/hugr-passes/src/dataflow/datalog.rs b/hugr-passes/src/dataflow/datalog.rs index 13e510daf..037ca2bda 100644 --- a/hugr-passes/src/dataflow/datalog.rs +++ b/hugr-passes/src/dataflow/datalog.rs @@ -401,6 +401,13 @@ fn propagate_leaf_op( outs })) } - o => todo!("Unhandled: {:?}", o), // At least CallIndirect, and OpType is "non-exhaustive" + OpType::CallIndirect(_) => Some(ValueRow::from_iter(if row_contains_bottom(ins) { + vec![PartialValue::Bottom; num_outs] + } else { + let mut outs = vec![PartialValue::Top; num_outs]; + ctx.interpret_call_indirect(&ins[0], &ins[1..], &mut outs[..]); + outs + })), + o => todo!("Unhandled: {:?}", o), // OpType is "non-exhaustive" } } From 55fc2334e64e075696470f31563d9dc03be659f6 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 31 Mar 2025 21:13:40 +0100 Subject: [PATCH 06/11] Handle CallIndirect in ConstFoldContext...by complete recursion --- hugr-passes/src/const_fold.rs | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/hugr-passes/src/const_fold.rs b/hugr-passes/src/const_fold.rs index 82803cf4d..6d43b888d 100644 --- a/hugr-passes/src/const_fold.rs +++ b/hugr-passes/src/const_fold.rs @@ -3,6 +3,7 @@ //! An (example) use of the [dataflow analysis framework](super::dataflow). mod value_handle; +use itertools::{Either, Itertools}; use std::{collections::HashMap, sync::Arc}; use thiserror::Error; @@ -257,6 +258,44 @@ impl> DFContext> for ConstFoldCont partial_from_const(self, ConstLocation::Field(p.index(), &node.into()), &v); } } + + fn interpret_call_indirect( + &mut self, + func: &PartialValue>, + args: &[PartialValue>], + outs: &mut [PartialValue>], + ) { + let PartialValue::Value(func) = func else { + return; + }; + let inputs = args.iter().cloned().enumerate().map(|(i, v)| (i.into(), v)); + let vals: Vec<_> = match func { + ValueHandle::NodeRef(node, _) => { + let mut m = Machine::new(self.0); + m.prepopulate_inputs(*node, inputs).unwrap(); + let results = m.run(ConstFoldContext(self.0), []); + (0..outs.len()) + .map(|p| results.read_out_wire(Wire::new(*node, p))) + .collect() + } + ValueHandle::Unhashable { + leaf: Either::Right(hugr), + .. + } => { + let h = hugr.as_ref(); + let results = Machine::new(h).run(ConstFoldContext(h), inputs); + (0..outs.len()) + .map(|p| results.read_out_wire(Wire::new(h.root(), p))) + .collect() + } + _ => return, + }; + for (val, out) in vals.into_iter().zip_eq(outs) { + if let Some(val) = val { + *out = val; + } + } + } } #[cfg(test)] From 3794f13822c5ce1372aec9c5885a2753d91586bd Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Tue, 1 Apr 2025 09:09:23 +0100 Subject: [PATCH 07/11] add constant_fold_with_hugr --- hugr-core/src/extension/const_fold.rs | 21 +++++++++++++++------ hugr-core/src/extension/op_def.rs | 20 +++++++++++++++++--- hugr-core/src/ops/custom.rs | 12 +++++++++++- hugr-passes/src/const_fold.rs | 5 ++++- 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/hugr-core/src/extension/const_fold.rs b/hugr-core/src/extension/const_fold.rs index a2cd66f42..daf0b6114 100644 --- a/hugr-core/src/extension/const_fold.rs +++ b/hugr-core/src/extension/const_fold.rs @@ -4,16 +4,12 @@ use std::fmt::Debug; use crate::ops::Value; use crate::types::TypeArg; - -use crate::IncomingPort; -use crate::OutgoingPort; - -use crate::ops; +use crate::{Hugr, IncomingPort, OutgoingPort}; /// Output of constant folding an operation, None indicates folding was either /// not possible or unsuccessful. An empty vector indicates folding was /// successful and no values are output. -pub type ConstFoldResult = Option>; +pub type ConstFoldResult = Option>; /// Tag some output constants with [`OutgoingPort`] inferred from the ordering. pub fn fold_out_row(consts: impl IntoIterator) -> ConstFoldResult { @@ -27,6 +23,19 @@ pub fn fold_out_row(consts: impl IntoIterator) -> ConstFoldResult /// Trait implemented by extension operations that can perform constant folding. pub trait ConstFold: Send + Sync { + /// Given the containing Hugr, type arguments `type_args` and [`crate::ops::Const`] + /// values for inputs at [`crate::IncomingPort`]s, try to evaluate the operation. + /// + /// Defaults to calling [Self::fold] (ignoring the Hugr) + fn fold_with_hugr( + &self, + type_args: &[TypeArg], + consts: &[(crate::IncomingPort, crate::ops::Value)], + _hugr: &Hugr, + ) -> ConstFoldResult { + self.fold(type_args, consts) + } + /// Given type arguments `type_args` and /// [`crate::ops::Const`] values for inputs at [`crate::IncomingPort`]s, /// try to evaluate the operation. diff --git a/hugr-core/src/extension/op_def.rs b/hugr-core/src/extension/op_def.rs index d5c9a5b5d..b3313bddf 100644 --- a/hugr-core/src/extension/op_def.rs +++ b/hugr-core/src/extension/op_def.rs @@ -9,10 +9,10 @@ use super::{ SignatureError, }; -use crate::ops::{OpName, OpNameRef}; +use crate::ops::{OpName, OpNameRef, Value}; use crate::types::type_param::{check_type_args, TypeArg, TypeParam}; use crate::types::{FuncValueType, PolyFuncType, PolyFuncTypeRV, Signature}; -use crate::Hugr; +use crate::{Hugr, IncomingPort}; mod serialize_signature_func; /// Trait necessary for binary computations of OpDef signature @@ -460,11 +460,25 @@ impl OpDef { pub fn constant_fold( &self, type_args: &[TypeArg], - consts: &[(crate::IncomingPort, crate::ops::Value)], + consts: &[(IncomingPort, Value)], ) -> ConstFoldResult { (self.constant_folder.as_ref())?.fold(type_args, consts) } + /// Evaluate an instance of this [`OpDef`] defined by the `type_args`, given + /// [`crate::ops::Const`] values for inputs at [`crate::IncomingPort`]s and + /// access to the containing Hugr. + pub fn constant_fold_with_hugr( + &self, + type_args: &[TypeArg], + consts: &[(IncomingPort, Value)], + hugr: &Hugr, + ) -> ConstFoldResult { + self.constant_folder + .as_ref()? + .fold_with_hugr(type_args, consts, hugr) + } + /// Returns a reference to the signature function of this [`OpDef`]. pub fn signature_func(&self) -> &SignatureFunc { &self.signature_func diff --git a/hugr-core/src/ops/custom.rs b/hugr-core/src/ops/custom.rs index 96e884f6d..e744838e2 100644 --- a/hugr-core/src/ops/custom.rs +++ b/hugr-core/src/ops/custom.rs @@ -14,7 +14,7 @@ use { use crate::extension::{ConstFoldResult, ExtensionId, OpDef, SignatureError}; use crate::types::{type_param::TypeArg, Signature}; -use crate::{ops, IncomingPort, Node}; +use crate::{ops, Hugr, IncomingPort, Node}; use super::dataflow::DataflowOpTrait; use super::tag::OpTag; @@ -96,6 +96,16 @@ impl ExtensionOp { self.def().constant_fold(self.args(), consts) } + /// Attempt to evaluate this operation, See ['OpDef::constant_fold_with_hugr`] + pub fn constant_fold_with_hugr( + &self, + consts: &[(IncomingPort, ops::Value)], + hugr: &Hugr, + ) -> ConstFoldResult { + self.def() + .constant_fold_with_hugr(self.args(), consts, hugr) + } + /// Creates a new [`OpaqueOp`] as a downgraded version of this /// [`ExtensionOp`]. /// diff --git a/hugr-passes/src/const_fold.rs b/hugr-passes/src/const_fold.rs index 6d43b888d..e79fba9ab 100644 --- a/hugr-passes/src/const_fold.rs +++ b/hugr-passes/src/const_fold.rs @@ -253,7 +253,10 @@ impl> DFContext> for ConstFoldCont .map(|v| (IncomingPort::from(i), v)) }) .collect::>(); - for (p, v) in op.constant_fold(&known_ins).unwrap_or_default() { + for (p, v) in op + .constant_fold_with_hugr(&known_ins, self.0.base_hugr()) + .unwrap_or_default() + { outs[p.index()] = partial_from_const(self, ConstLocation::Field(p.index(), &node.into()), &v); } From 6d8f250d468e46ed3156c137f292726169ab1199 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Wed, 2 Apr 2025 10:25:09 +0100 Subject: [PATCH 08/11] Revert "add constant_fold_with_hugr" This reverts commit 3794f13822c5ce1372aec9c5885a2753d91586bd. --- hugr-core/src/extension/const_fold.rs | 21 ++++++--------------- hugr-core/src/extension/op_def.rs | 20 +++----------------- hugr-core/src/ops/custom.rs | 12 +----------- hugr-passes/src/const_fold.rs | 5 +---- 4 files changed, 11 insertions(+), 47 deletions(-) diff --git a/hugr-core/src/extension/const_fold.rs b/hugr-core/src/extension/const_fold.rs index daf0b6114..a2cd66f42 100644 --- a/hugr-core/src/extension/const_fold.rs +++ b/hugr-core/src/extension/const_fold.rs @@ -4,12 +4,16 @@ use std::fmt::Debug; use crate::ops::Value; use crate::types::TypeArg; -use crate::{Hugr, IncomingPort, OutgoingPort}; + +use crate::IncomingPort; +use crate::OutgoingPort; + +use crate::ops; /// Output of constant folding an operation, None indicates folding was either /// not possible or unsuccessful. An empty vector indicates folding was /// successful and no values are output. -pub type ConstFoldResult = Option>; +pub type ConstFoldResult = Option>; /// Tag some output constants with [`OutgoingPort`] inferred from the ordering. pub fn fold_out_row(consts: impl IntoIterator) -> ConstFoldResult { @@ -23,19 +27,6 @@ pub fn fold_out_row(consts: impl IntoIterator) -> ConstFoldResult /// Trait implemented by extension operations that can perform constant folding. pub trait ConstFold: Send + Sync { - /// Given the containing Hugr, type arguments `type_args` and [`crate::ops::Const`] - /// values for inputs at [`crate::IncomingPort`]s, try to evaluate the operation. - /// - /// Defaults to calling [Self::fold] (ignoring the Hugr) - fn fold_with_hugr( - &self, - type_args: &[TypeArg], - consts: &[(crate::IncomingPort, crate::ops::Value)], - _hugr: &Hugr, - ) -> ConstFoldResult { - self.fold(type_args, consts) - } - /// Given type arguments `type_args` and /// [`crate::ops::Const`] values for inputs at [`crate::IncomingPort`]s, /// try to evaluate the operation. diff --git a/hugr-core/src/extension/op_def.rs b/hugr-core/src/extension/op_def.rs index b3313bddf..d5c9a5b5d 100644 --- a/hugr-core/src/extension/op_def.rs +++ b/hugr-core/src/extension/op_def.rs @@ -9,10 +9,10 @@ use super::{ SignatureError, }; -use crate::ops::{OpName, OpNameRef, Value}; +use crate::ops::{OpName, OpNameRef}; use crate::types::type_param::{check_type_args, TypeArg, TypeParam}; use crate::types::{FuncValueType, PolyFuncType, PolyFuncTypeRV, Signature}; -use crate::{Hugr, IncomingPort}; +use crate::Hugr; mod serialize_signature_func; /// Trait necessary for binary computations of OpDef signature @@ -460,25 +460,11 @@ impl OpDef { pub fn constant_fold( &self, type_args: &[TypeArg], - consts: &[(IncomingPort, Value)], + consts: &[(crate::IncomingPort, crate::ops::Value)], ) -> ConstFoldResult { (self.constant_folder.as_ref())?.fold(type_args, consts) } - /// Evaluate an instance of this [`OpDef`] defined by the `type_args`, given - /// [`crate::ops::Const`] values for inputs at [`crate::IncomingPort`]s and - /// access to the containing Hugr. - pub fn constant_fold_with_hugr( - &self, - type_args: &[TypeArg], - consts: &[(IncomingPort, Value)], - hugr: &Hugr, - ) -> ConstFoldResult { - self.constant_folder - .as_ref()? - .fold_with_hugr(type_args, consts, hugr) - } - /// Returns a reference to the signature function of this [`OpDef`]. pub fn signature_func(&self) -> &SignatureFunc { &self.signature_func diff --git a/hugr-core/src/ops/custom.rs b/hugr-core/src/ops/custom.rs index e744838e2..96e884f6d 100644 --- a/hugr-core/src/ops/custom.rs +++ b/hugr-core/src/ops/custom.rs @@ -14,7 +14,7 @@ use { use crate::extension::{ConstFoldResult, ExtensionId, OpDef, SignatureError}; use crate::types::{type_param::TypeArg, Signature}; -use crate::{ops, Hugr, IncomingPort, Node}; +use crate::{ops, IncomingPort, Node}; use super::dataflow::DataflowOpTrait; use super::tag::OpTag; @@ -96,16 +96,6 @@ impl ExtensionOp { self.def().constant_fold(self.args(), consts) } - /// Attempt to evaluate this operation, See ['OpDef::constant_fold_with_hugr`] - pub fn constant_fold_with_hugr( - &self, - consts: &[(IncomingPort, ops::Value)], - hugr: &Hugr, - ) -> ConstFoldResult { - self.def() - .constant_fold_with_hugr(self.args(), consts, hugr) - } - /// Creates a new [`OpaqueOp`] as a downgraded version of this /// [`ExtensionOp`]. /// diff --git a/hugr-passes/src/const_fold.rs b/hugr-passes/src/const_fold.rs index e79fba9ab..6d43b888d 100644 --- a/hugr-passes/src/const_fold.rs +++ b/hugr-passes/src/const_fold.rs @@ -253,10 +253,7 @@ impl> DFContext> for ConstFoldCont .map(|v| (IncomingPort::from(i), v)) }) .collect::>(); - for (p, v) in op - .constant_fold_with_hugr(&known_ins, self.0.base_hugr()) - .unwrap_or_default() - { + for (p, v) in op.constant_fold(&known_ins).unwrap_or_default() { outs[p.index()] = partial_from_const(self, ConstLocation::Field(p.index(), &node.into()), &v); } From 26045398c137c61b239e4dfe8499647d129210dc Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Wed, 2 Apr 2025 10:28:06 +0100 Subject: [PATCH 09/11] Revert "Hide value_handle, no need for it to be public" This reverts commit 3f764ecce865339f444024f8b3b209fa8365b077. --- hugr-passes/src/const_fold.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hugr-passes/src/const_fold.rs b/hugr-passes/src/const_fold.rs index 6d43b888d..590b2476f 100644 --- a/hugr-passes/src/const_fold.rs +++ b/hugr-passes/src/const_fold.rs @@ -2,7 +2,7 @@ //! Constant-folding pass. //! An (example) use of the [dataflow analysis framework](super::dataflow). -mod value_handle; +pub mod value_handle; use itertools::{Either, Itertools}; use std::{collections::HashMap, sync::Arc}; use thiserror::Error; From a119e07cc1b778d01df0aae769d3d6d9e1db6e91 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Wed, 2 Apr 2025 10:45:41 +0100 Subject: [PATCH 10/11] relax Node=Node constraint for ConstLoader --- hugr-passes/src/const_fold.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hugr-passes/src/const_fold.rs b/hugr-passes/src/const_fold.rs index 590b2476f..7c88a50fa 100644 --- a/hugr-passes/src/const_fold.rs +++ b/hugr-passes/src/const_fold.rs @@ -204,7 +204,7 @@ pub fn constant_fold_pass(h: &mut H) { struct ConstFoldContext<'a, H>(&'a H); -impl> ConstLoader> for ConstFoldContext<'_, H> { +impl ConstLoader> for ConstFoldContext<'_, H> { type Node = H::Node; fn value_from_opaque( From 482a4354157b2219893860ab146716301a920591 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Wed, 2 Apr 2025 10:45:56 +0100 Subject: [PATCH 11/11] note why we can't relax Node=Node for DFContext --- hugr-passes/src/const_fold.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hugr-passes/src/const_fold.rs b/hugr-passes/src/const_fold.rs index 7c88a50fa..37f3eb6e0 100644 --- a/hugr-passes/src/const_fold.rs +++ b/hugr-passes/src/const_fold.rs @@ -283,6 +283,13 @@ impl> DFContext> for ConstFoldCont .. } => { let h = hugr.as_ref(); + // The problem here---which we'd see if we didn't constrain H::Node==Node, + // because the ValueHandle's would be incompatible---is that `args` may contain + // (a) UnhashableConsts keyed by NodeId in the *outer* Hugr (`self.0`, not `h`). + // (b) NodeRefs referring to nodes in the outer Hugr ! + // + // We can solve the first by remapping keys of HashedConsts to the input ports + // (like `fresh_node` in ConstFoldContext::run_no_validate), but not the second. let results = Machine::new(h).run(ConstFoldContext(h), inputs); (0..outs.len()) .map(|p| results.read_out_wire(Wire::new(h.root(), p)))