diff --git a/hugr-cli/tests/cli.rs b/hugr-cli/tests/cli.rs index 1cd8b5438..ac98b2aa7 100644 --- a/hugr-cli/tests/cli.rs +++ b/hugr-cli/tests/cli.rs @@ -12,7 +12,7 @@ use hugr_core::{ builder::{Container, Dataflow, DataflowHugr}, extension::prelude::{BOOL_T, QB_T}, type_row, - types::FunctionType, + types::Signature, Hugr, }; use predicates::{prelude::*, str::contains}; @@ -25,7 +25,7 @@ fn cmd() -> Command { #[fixture] fn test_hugr() -> Hugr { - let df = DFGBuilder::new(FunctionType::new_endo(type_row![BOOL_T])).unwrap(); + let df = DFGBuilder::new(Signature::new_endo(type_row![BOOL_T])).unwrap(); let [i] = df.input_wires_arr(); df.finish_prelude_hugr_with_outputs([i]).unwrap() } @@ -83,7 +83,7 @@ fn test_mermaid(test_hugr_file: NamedTempFile, mut cmd: Command) { #[rstest] fn test_bad_hugr(mut cmd: Command) { - let df = DFGBuilder::new(FunctionType::new_endo(type_row![QB_T])).unwrap(); + let df = DFGBuilder::new(Signature::new_endo(type_row![QB_T])).unwrap(); let bad_hugr = df.hugr().clone(); let bad_hugr_string = serde_json::to_string(&bad_hugr).unwrap(); diff --git a/hugr-core/src/builder.rs b/hugr-core/src/builder.rs index 7502f8275..3dd368a68 100644 --- a/hugr-core/src/builder.rs +++ b/hugr-core/src/builder.rs @@ -30,7 +30,7 @@ //! # use hugr::builder::{BuildError, BuildHandle, Container, DFGBuilder, Dataflow, DataflowHugr, ModuleBuilder, DataflowSubContainer, HugrBuilder}; //! use hugr::extension::prelude::BOOL_T; //! use hugr::std_extensions::logic::{EXTENSION_ID, LOGIC_REG, NotOp}; -//! use hugr::types::FunctionType; +//! use hugr::types::Signature; //! //! # fn doctest() -> Result<(), BuildError> { //! let hugr = { @@ -42,7 +42,7 @@ //! let _dfg_handle = { //! let mut dfg = module_builder.define_function( //! "main", -//! FunctionType::new_endo(BOOL_T).with_extension_delta(EXTENSION_ID), +//! Signature::new_endo(BOOL_T).with_extension_delta(EXTENSION_ID), //! )?; //! //! // Get the wires from the function inputs. @@ -59,7 +59,7 @@ //! let _circuit_handle = { //! let mut dfg = module_builder.define_function( //! "circuit", -//! FunctionType::new_endo(vec![BOOL_T, BOOL_T]) +//! Signature::new_endo(vec![BOOL_T, BOOL_T]) //! .with_extension_delta(EXTENSION_ID), //! )?; //! let mut circuit = dfg.as_circuit(dfg.input_wires()); @@ -93,7 +93,7 @@ use crate::hugr::ValidationError; use crate::ops::handle::{BasicBlockID, CfgID, ConditionalID, DfgID, FuncID, TailLoopID}; use crate::ops::{NamedOp, OpType}; use crate::types::Type; -use crate::types::{ConstTypeError, FunctionType, TypeRow}; +use crate::types::{ConstTypeError, Signature, TypeRow}; use crate::{Node, Port, Wire}; pub mod handle; @@ -124,14 +124,14 @@ pub use circuit::{CircuitBuildError, CircuitBuilder}; /// Return a FunctionType with the same input and output types (specified) /// whose extension delta, when used in a non-FuncDefn container, will be inferred. -pub fn endo_ft(types: impl Into) -> FunctionType { - FunctionType::new_endo(types).with_extension_delta(TO_BE_INFERRED) +pub fn endo_sig(types: impl Into) -> Signature { + Signature::new_endo(types).with_extension_delta(TO_BE_INFERRED) } /// Return a FunctionType with the specified input and output types /// whose extension delta, when used in a non-FuncDefn container, will be inferred. -pub fn inout_ft(inputs: impl Into, outputs: impl Into) -> FunctionType { - FunctionType::new(inputs, outputs).with_extension_delta(TO_BE_INFERRED) +pub fn inout_sig(inputs: impl Into, outputs: impl Into) -> Signature { + Signature::new(inputs, outputs).with_extension_delta(TO_BE_INFERRED) } #[derive(Debug, Clone, PartialEq, Error)] @@ -236,7 +236,7 @@ pub(crate) mod test { use crate::hugr::{views::HugrView, HugrMut}; use crate::ops; use crate::std_extensions::arithmetic::float_ops::FLOAT_OPS_REGISTRY; - use crate::types::{FunctionType, PolyFuncType, Type}; + use crate::types::{PolyFuncType, Signature, Type}; use crate::{type_row, Hugr}; use super::handle::BuildHandle; @@ -272,8 +272,7 @@ pub(crate) mod test { #[fixture] pub(crate) fn simple_dfg_hugr() -> Hugr { - let dfg_builder = - DFGBuilder::new(FunctionType::new(type_row![BIT], type_row![BIT])).unwrap(); + let dfg_builder = DFGBuilder::new(Signature::new(type_row![BIT], type_row![BIT])).unwrap(); let [i1] = dfg_builder.input_wires_arr(); dfg_builder.finish_prelude_hugr_with_outputs([i1]).unwrap() } @@ -281,7 +280,7 @@ pub(crate) mod test { #[fixture] pub(crate) fn simple_cfg_hugr() -> Hugr { let mut cfg_builder = - CFGBuilder::new(FunctionType::new(type_row![NAT], type_row![NAT])).unwrap(); + CFGBuilder::new(Signature::new(type_row![NAT], type_row![NAT])).unwrap(); super::cfg::test::build_basic_cfg(&mut cfg_builder).unwrap(); cfg_builder.finish_prelude_hugr().unwrap() } @@ -289,7 +288,7 @@ pub(crate) mod test { /// A helper method which creates a DFG rooted hugr with Input and Output node /// only (no wires), given a function type with extension delta. // TODO consider taking two type rows and using TO_BE_INFERRED - pub(crate) fn closed_dfg_root_hugr(signature: FunctionType) -> Hugr { + pub(crate) fn closed_dfg_root_hugr(signature: Signature) -> Hugr { let mut hugr = Hugr::new(ops::DFG { signature: signature.clone(), }); diff --git a/hugr-core/src/builder/build_traits.rs b/hugr-core/src/builder/build_traits.rs index 3c72d0d43..e91c36782 100644 --- a/hugr-core/src/builder/build_traits.rs +++ b/hugr-core/src/builder/build_traits.rs @@ -18,10 +18,8 @@ use crate::{ types::EdgeKind, }; -use crate::extension::{ - ExtensionRegistry, ExtensionSet, SignatureError, PRELUDE_REGISTRY, TO_BE_INFERRED, -}; -use crate::types::{FunctionType, PolyFuncType, Type, TypeArg, TypeRow}; +use crate::extension::{ExtensionRegistry, ExtensionSet, PRELUDE_REGISTRY, TO_BE_INFERRED}; +use crate::types::{PolyFuncType, Signature, Type, TypeArg, TypeRow}; use itertools::Itertools; @@ -276,7 +274,7 @@ pub trait Dataflow: Container { // TODO: Should this be one function, or should there be a temporary "op" one like with the others? fn dfg_builder( &mut self, - signature: FunctionType, + signature: Signature, input_wires: impl IntoIterator, ) -> Result, BuildError> { let op = ops::DFG { @@ -297,7 +295,7 @@ pub trait Dataflow: Container { ) -> Result, BuildError> { let (types, input_wires): (Vec, Vec) = inputs.into_iter().unzip(); self.dfg_builder( - FunctionType::new_endo(types).with_extension_delta(TO_BE_INFERRED), + Signature::new_endo(types).with_extension_delta(TO_BE_INFERRED), input_wires, ) } @@ -325,7 +323,7 @@ pub trait Dataflow: Container { let (cfg_node, _) = add_node_with_wires( self, ops::CFG { - signature: FunctionType::new(inputs.clone(), output_types.clone()) + signature: Signature::new(inputs.clone(), output_types.clone()) .with_extension_delta(extension_delta), }, input_wires, @@ -658,14 +656,6 @@ fn add_node_with_wires( inputs: impl IntoIterator, ) -> Result<(Node, usize), BuildError> { let op = nodetype.into(); - // Check there are no row variables, as that would prevent us - // from indexing into the node's ports in order to wire up - op.dataflow_signature() - .as_ref() - .and_then(FunctionType::find_rowvar) - .map_or(Ok(()), |(idx, _)| { - Err(SignatureError::RowVarWhereTypeExpected { idx }) - })?; let num_outputs = op.value_output_count(); let op_node = data_builder.add_child_node(op.clone()); diff --git a/hugr-core/src/builder/cfg.rs b/hugr-core/src/builder/cfg.rs index 0d37992d0..8f974d8c5 100644 --- a/hugr-core/src/builder/cfg.rs +++ b/hugr-core/src/builder/cfg.rs @@ -11,7 +11,7 @@ use crate::{ }; use crate::{ extension::{ExtensionRegistry, ExtensionSet}, - types::FunctionType, + types::Signature, }; use crate::{hugr::views::HugrView, types::TypeRow}; @@ -46,17 +46,17 @@ use crate::{hugr::HugrMut, type_row, Hugr}; /// +------------+ /// */ /// use hugr::{ -/// builder::{BuildError, CFGBuilder, Container, Dataflow, HugrBuilder, endo_ft, inout_ft}, +/// builder::{BuildError, CFGBuilder, Container, Dataflow, HugrBuilder, endo_sig, inout_sig}, /// extension::{prelude, ExtensionSet}, /// ops, type_row, -/// types::{FunctionType, SumType, Type}, +/// types::{Signature, SumType, Type}, /// Hugr, /// }; /// /// const NAT: Type = prelude::USIZE_T; /// /// fn make_cfg() -> Result { -/// let mut cfg_builder = CFGBuilder::new(FunctionType::new(type_row![NAT], type_row![NAT]))?; +/// let mut cfg_builder = CFGBuilder::new(Signature::new_endo(NAT))?; /// /// // Outputs from basic blocks must be packed in a sum which corresponds to /// // which successor to pick. We'll either choose the first branch and pass @@ -84,7 +84,7 @@ use crate::{hugr::HugrMut, type_row, Hugr}; /// // `NAT` arguments: one from the `sum_variants` type, and another from the /// // entry node's `other_outputs`. /// let mut successor_builder = cfg_builder.simple_block_builder( -/// inout_ft(type_row![NAT, NAT], NAT), +/// inout_sig(type_row![NAT, NAT], NAT), /// 1, // only one successor to this block /// )?; /// let successor_a = { @@ -98,7 +98,7 @@ use crate::{hugr::HugrMut, type_row, Hugr}; /// }; /// /// // The only argument to this block is the entry node's `other_outputs`. -/// let mut successor_builder = cfg_builder.simple_block_builder(endo_ft(NAT), 1)?; +/// let mut successor_builder = cfg_builder.simple_block_builder(endo_sig(NAT), 1)?; /// let successor_b = { /// let sum_unary = successor_builder.add_load_value(ops::Value::unary_unit_sum()); /// let [in_wire] = successor_builder.input_wires_arr(); @@ -151,7 +151,7 @@ impl + AsRef> SubContainer for CFGBuilder { impl CFGBuilder { /// New CFG rooted HUGR builder - pub fn new(signature: FunctionType) -> Result { + pub fn new(signature: Signature) -> Result { let cfg_op = ops::CFG { signature: signature.clone(), }; @@ -272,7 +272,7 @@ impl + AsRef> CFGBuilder { /// This function will return an error if there is an error adding the node. pub fn simple_block_builder( &mut self, - signature: FunctionType, + signature: Signature, n_cases: usize, ) -> Result, BuildError> { self.block_builder_exts( @@ -463,7 +463,7 @@ pub(crate) mod test { let build_result = { let mut module_builder = ModuleBuilder::new(); let mut func_builder = module_builder - .define_function("main", FunctionType::new(vec![NAT], type_row![NAT]))?; + .define_function("main", Signature::new(vec![NAT], type_row![NAT]))?; let _f_id = { let [int] = func_builder.input_wires_arr(); @@ -489,7 +489,7 @@ pub(crate) mod test { } #[test] fn basic_cfg_hugr() -> Result<(), BuildError> { - let mut cfg_builder = CFGBuilder::new(FunctionType::new(type_row![NAT], type_row![NAT]))?; + let mut cfg_builder = CFGBuilder::new(Signature::new(type_row![NAT], type_row![NAT]))?; build_basic_cfg(&mut cfg_builder)?; assert_matches!(cfg_builder.finish_prelude_hugr(), Ok(_)); @@ -511,8 +511,8 @@ pub(crate) mod test { let sum = entry_b.make_sum(1, sum2_variants, [inw])?; entry_b.finish_with_outputs(sum, [])? }; - let mut middle_b = cfg_builder - .simple_block_builder(FunctionType::new(type_row![NAT], type_row![NAT]), 1)?; + let mut middle_b = + cfg_builder.simple_block_builder(Signature::new(type_row![NAT], type_row![NAT]), 1)?; let middle = { let c = middle_b.add_load_const(ops::Value::unary_unit_sum()); let [inw] = middle_b.input_wires_arr(); @@ -526,7 +526,7 @@ pub(crate) mod test { } #[test] fn test_dom_edge() -> Result<(), BuildError> { - let mut cfg_builder = CFGBuilder::new(FunctionType::new(type_row![NAT], type_row![NAT]))?; + let mut cfg_builder = CFGBuilder::new(Signature::new(type_row![NAT], type_row![NAT]))?; let sum_tuple_const = cfg_builder.add_constant(ops::Value::unary_unit_sum()); let sum_variants = vec![type_row![]]; @@ -542,7 +542,7 @@ pub(crate) mod test { entry_b.finish_with_outputs(sum, [])? }; let mut middle_b = - cfg_builder.simple_block_builder(FunctionType::new(type_row![], type_row![NAT]), 1)?; + cfg_builder.simple_block_builder(Signature::new(type_row![], type_row![NAT]), 1)?; let middle = { let c = middle_b.load_const(&sum_tuple_const); middle_b.finish_with_outputs(c, [inw])? @@ -557,11 +557,11 @@ pub(crate) mod test { #[test] fn test_non_dom_edge() -> Result<(), BuildError> { - let mut cfg_builder = CFGBuilder::new(FunctionType::new(type_row![NAT], type_row![NAT]))?; + let mut cfg_builder = CFGBuilder::new(Signature::new(type_row![NAT], type_row![NAT]))?; let sum_tuple_const = cfg_builder.add_constant(ops::Value::unary_unit_sum()); let sum_variants = vec![type_row![]]; - let mut middle_b = cfg_builder - .simple_block_builder(FunctionType::new(type_row![NAT], type_row![NAT]), 1)?; + let mut middle_b = + cfg_builder.simple_block_builder(Signature::new(type_row![NAT], type_row![NAT]), 1)?; let [inw] = middle_b.input_wires_arr(); let middle = { let c = middle_b.load_const(&sum_tuple_const); diff --git a/hugr-core/src/builder/circuit.rs b/hugr-core/src/builder/circuit.rs index 272ddead5..c9f92466b 100644 --- a/hugr-core/src/builder/circuit.rs +++ b/hugr-core/src/builder/circuit.rs @@ -254,13 +254,13 @@ mod test { extension::prelude::BOOL_T, ops::{custom::OpaqueOp, CustomOp}, type_row, - types::FunctionType, + types::Signature, }; #[test] fn simple_linear() { let build_res = build_main( - FunctionType::new(type_row![QB, QB], type_row![QB, QB]) + Signature::new(type_row![QB, QB], type_row![QB, QB]) .with_extension_delta(test_quantum_extension::EXTENSION_ID) .with_extension_delta(float_types::EXTENSION_ID) .into(), @@ -300,10 +300,10 @@ mod test { "MyOp", "unknown op".to_string(), vec![], - FunctionType::new(vec![QB, NAT], vec![QB]), + Signature::new(vec![QB, NAT], vec![QB]), )); let build_res = build_main( - FunctionType::new(type_row![QB, QB, NAT], type_row![QB, QB, BOOL_T]) + Signature::new(type_row![QB, QB, NAT], type_row![QB, QB, BOOL_T]) .with_extension_delta(test_quantum_extension::EXTENSION_ID) .into(), |mut f_build| { @@ -330,7 +330,7 @@ mod test { #[test] fn ancillae() { let build_res = build_main( - FunctionType::new_endo(QB) + Signature::new_endo(QB) .with_extension_delta(test_quantum_extension::EXTENSION_ID) .into(), |mut f_build| { @@ -368,7 +368,7 @@ mod test { #[test] fn circuit_builder_errors() { let _build_res = build_main( - FunctionType::new_endo(type_row![QB, QB]).into(), + Signature::new_endo(type_row![QB, QB]).into(), |mut f_build| { let mut circ = f_build.as_circuit(f_build.input_wires()); let [q0, q1] = circ.tracked_units_arr(); diff --git a/hugr-core/src/builder/conditional.rs b/hugr-core/src/builder/conditional.rs index bfdd859a5..e4e56cdc1 100644 --- a/hugr-core/src/builder/conditional.rs +++ b/hugr-core/src/builder/conditional.rs @@ -1,7 +1,7 @@ use crate::extension::ExtensionRegistry; use crate::hugr::views::HugrView; use crate::ops::dataflow::DataflowOpTrait; -use crate::types::{FunctionType, TypeRow}; +use crate::types::{Signature, TypeRow}; use crate::ops; use crate::ops::handle::CaseID; @@ -118,7 +118,7 @@ impl + AsRef> ConditionalBuilder { let outputs = cond.outputs; let case_op = ops::Case { - signature: FunctionType::new(inputs.clone(), outputs.clone()) + signature: Signature::new(inputs.clone(), outputs.clone()) .with_extension_delta(extension_delta.clone()), }; let case_node = @@ -134,7 +134,7 @@ impl + AsRef> ConditionalBuilder { let dfg_builder = DFGBuilder::create_with_io( self.hugr_mut(), case_node, - FunctionType::new(inputs, outputs).with_extension_delta(extension_delta), + Signature::new(inputs, outputs).with_extension_delta(extension_delta), )?; Ok(CaseBuilder::from_dfg_builder(dfg_builder)) @@ -186,7 +186,7 @@ impl ConditionalBuilder { impl CaseBuilder { /// Initialize a Case rooted HUGR - pub fn new(signature: FunctionType) -> Result { + pub fn new(signature: Signature) -> Result { let op = ops::Case { signature: signature.clone(), }; @@ -233,7 +233,7 @@ mod test { let build_result: Result = { let mut module_builder = ModuleBuilder::new(); let mut fbuild = module_builder - .define_function("main", FunctionType::new(type_row![NAT], type_row![NAT]))?; + .define_function("main", Signature::new(type_row![NAT], type_row![NAT]))?; let tru_const = fbuild.add_constant(Value::true_val()); let _fdef = { let const_wire = fbuild.load_const(&tru_const); diff --git a/hugr-core/src/builder/dataflow.rs b/hugr-core/src/builder/dataflow.rs index 4a5f4e723..72dbee910 100644 --- a/hugr-core/src/builder/dataflow.rs +++ b/hugr-core/src/builder/dataflow.rs @@ -7,7 +7,7 @@ use std::marker::PhantomData; use crate::hugr::{HugrView, ValidationError}; use crate::ops; -use crate::types::{FunctionType, PolyFuncType}; +use crate::types::{PolyFuncType, Signature}; use crate::extension::ExtensionRegistry; use crate::Node; @@ -26,7 +26,7 @@ impl + AsRef> DFGBuilder { pub(super) fn create_with_io( mut base: T, parent: Node, - signature: FunctionType, + signature: Signature, ) -> Result { let num_in_wires = signature.input().len(); let num_out_wires = signature.output().len(); @@ -67,7 +67,7 @@ impl DFGBuilder { /// # Errors /// /// Error in adding DFG child nodes. - pub fn new(signature: FunctionType) -> Result, BuildError> { + pub fn new(signature: Signature) -> Result, BuildError> { let dfg_op = ops::DFG { signature: signature.clone(), }; @@ -204,7 +204,7 @@ pub(crate) mod test { use crate::builder::build_traits::DataflowHugr; use crate::builder::{ - endo_ft, inout_ft, BuilderWiringError, DataflowSubContainer, ModuleBuilder, + endo_sig, inout_sig, BuilderWiringError, DataflowSubContainer, ModuleBuilder, }; use crate::extension::prelude::{BOOL_T, USIZE_T}; use crate::extension::{ExtensionId, SignatureError, EMPTY_REG, PRELUDE_REGISTRY}; @@ -214,7 +214,7 @@ pub(crate) mod test { use crate::std_extensions::logic::test::and_op; use crate::types::type_param::TypeParam; - use crate::types::{EdgeKind, Type, TypeBound}; + use crate::types::{EdgeKind, FuncValueType, RowVariable, Signature, Type, TypeBound, TypeRV}; use crate::utils::test_quantum_extension::h_gate; use crate::{ builder::test::{n_identity, BIT, NAT, QB}, @@ -226,7 +226,7 @@ pub(crate) mod test { #[test] fn nested_identity() -> Result<(), BuildError> { let build_result = { - let mut outer_builder = DFGBuilder::new(endo_ft(type_row![NAT, QB]))?; + let mut outer_builder = DFGBuilder::new(endo_sig(type_row![NAT, QB]))?; let [int, qb] = outer_builder.input_wires_arr(); @@ -250,7 +250,7 @@ pub(crate) mod test { F: FnOnce(&mut DFGBuilder) -> Result<(), BuildError>, { let build_result = { - let mut builder = DFGBuilder::new(inout_ft(BOOL_T, type_row![BOOL_T, BOOL_T]))?; + let mut builder = DFGBuilder::new(inout_sig(BOOL_T, type_row![BOOL_T, BOOL_T]))?; f(&mut builder)?; @@ -298,7 +298,7 @@ pub(crate) mod test { let mut module_builder = ModuleBuilder::new(); let f_build = module_builder - .define_function("main", FunctionType::new(type_row![QB], type_row![QB, QB]))?; + .define_function("main", Signature::new(type_row![QB], type_row![QB, QB]))?; let [q1] = f_build.input_wires_arr(); f_build.finish_with_outputs([q1, q1])?; @@ -320,14 +320,14 @@ pub(crate) mod test { fn simple_inter_graph_edge() { let builder = || -> Result { let mut f_build = - FunctionBuilder::new("main", FunctionType::new(type_row![BIT], type_row![BIT]))?; + FunctionBuilder::new("main", Signature::new(type_row![BIT], type_row![BIT]))?; let [i1] = f_build.input_wires_arr(); let noop = f_build.add_dataflow_op(Noop { ty: BIT }, [i1])?; let i1 = noop.out_wire(0); let mut nested = - f_build.dfg_builder(FunctionType::new(type_row![], type_row![BIT]), [])?; + f_build.dfg_builder(Signature::new(type_row![], type_row![BIT]), [])?; let id = nested.add_dataflow_op(Noop { ty: BIT }, [i1])?; @@ -342,13 +342,13 @@ pub(crate) mod test { #[test] fn error_on_linear_inter_graph_edge() -> Result<(), BuildError> { let mut f_build = - FunctionBuilder::new("main", FunctionType::new(type_row![QB], type_row![QB]))?; + FunctionBuilder::new("main", Signature::new(type_row![QB], type_row![QB]))?; let [i1] = f_build.input_wires_arr(); let noop = f_build.add_dataflow_op(Noop { ty: QB }, [i1])?; let i1 = noop.out_wire(0); - let mut nested = f_build.dfg_builder(FunctionType::new(type_row![], type_row![QB]), [])?; + let mut nested = f_build.dfg_builder(Signature::new(type_row![], type_row![QB]), [])?; let id_res = nested.add_dataflow_op(Noop { ty: QB }, [i1]); @@ -374,7 +374,7 @@ pub(crate) mod test { #[test] fn insert_hugr() -> Result<(), BuildError> { // Create a simple DFG - let mut dfg_builder = DFGBuilder::new(FunctionType::new(type_row![BIT], type_row![BIT]))?; + let mut dfg_builder = DFGBuilder::new(Signature::new(type_row![BIT], type_row![BIT]))?; let [i1] = dfg_builder.input_wires_arr(); dfg_builder.set_metadata("x", 42); let dfg_hugr = dfg_builder.finish_hugr_with_outputs([i1], &EMPTY_REG)?; @@ -384,7 +384,7 @@ pub(crate) mod test { let (dfg_node, f_node) = { let mut f_build = module_builder - .define_function("main", FunctionType::new(type_row![BIT], type_row![BIT]))?; + .define_function("main", Signature::new(type_row![BIT], type_row![BIT]))?; let [i1] = f_build.input_wires_arr(); let dfg = f_build.add_hugr_with_wires(dfg_hugr, [i1])?; @@ -409,12 +409,12 @@ pub(crate) mod test { let xb: ExtensionId = "B".try_into().unwrap(); let xc: ExtensionId = "C".try_into().unwrap(); - let mut parent = DFGBuilder::new(endo_ft(BIT))?; + let mut parent = DFGBuilder::new(endo_sig(BIT))?; let [w] = parent.input_wires_arr(); // A box which adds extensions A and B, via child Lift nodes - let mut add_ab = parent.dfg_builder(endo_ft(BIT), [w])?; + let mut add_ab = parent.dfg_builder(endo_sig(BIT), [w])?; let [w] = add_ab.input_wires_arr(); let lift_a = add_ab.add_dataflow_op( @@ -440,7 +440,7 @@ pub(crate) mod test { // Add another node (a sibling to add_ab) which adds extension C // via a child lift node - let mut add_c = parent.dfg_builder(endo_ft(BIT), [w])?; + let mut add_c = parent.dfg_builder(endo_sig(BIT), [w])?; let [w] = add_c.input_wires_arr(); let lift_c = add_c.add_dataflow_op( Lift { @@ -460,7 +460,7 @@ pub(crate) mod test { #[test] fn non_cfg_ancestor() -> Result<(), BuildError> { - let unit_sig = FunctionType::new(type_row![Type::UNIT], type_row![Type::UNIT]); + let unit_sig = Signature::new(type_row![Type::UNIT], type_row![Type::UNIT]); let mut b = DFGBuilder::new(unit_sig.clone())?; let b_child = b.dfg_builder(unit_sig.clone(), [b.input().out_wire(0)])?; let b_child_in_wire = b_child.input().out_wire(0); @@ -484,7 +484,7 @@ pub(crate) mod test { #[test] fn no_relation_edge() -> Result<(), BuildError> { - let unit_sig = FunctionType::new(type_row![Type::UNIT], type_row![Type::UNIT]); + let unit_sig = Signature::new(type_row![Type::UNIT], type_row![Type::UNIT]); let mut b = DFGBuilder::new(unit_sig.clone())?; let mut b_child = b.dfg_builder(unit_sig.clone(), [b.input().out_wire(0)])?; let b_child_child = b_child.dfg_builder(unit_sig.clone(), [b_child.input().out_wire(0)])?; @@ -512,30 +512,30 @@ pub(crate) mod test { #[test] fn no_outer_row_variables() -> Result<(), BuildError> { let e = crate::hugr::validate::test::extension_with_eval_parallel(); - let tv = Type::new_row_var_use(0, TypeBound::Copyable); - let mut fb = FunctionBuilder::new( + let tv = TypeRV::new_row_var_use(0, TypeBound::Copyable); + // Can *declare* a function that takes a function-value of unknown #args + FunctionBuilder::new( "bad_eval", PolyFuncType::new( [TypeParam::new_list(TypeBound::Copyable)], - FunctionType::new( - Type::new_function(FunctionType::new(USIZE_T, tv.clone())), + Signature::new( + Type::new_function(FuncValueType::new(USIZE_T, tv.clone())), vec![], ), ), )?; - let [func_arg] = fb.input_wires_arr(); - let i = fb.add_load_value(crate::extension::prelude::ConstUsize::new(5)); + // But cannot eval it... let ev = e.instantiate_extension_op( "eval", [vec![USIZE_T.into()].into(), vec![tv.into()].into()], &PRELUDE_REGISTRY, - )?; - let r = fb.add_dataflow_op(ev, [func_arg, i]); - // This error would be caught in validation, but the builder detects it much earlier + ); assert_eq!( - r.unwrap_err(), - BuildError::SignatureError(SignatureError::RowVarWhereTypeExpected { idx: 0 }) + ev, + Err(SignatureError::RowVarWhereTypeExpected { + var: RowVariable(0, TypeBound::Copyable) + }) ); Ok(()) } @@ -545,11 +545,11 @@ pub(crate) mod test { let (mut hugr, load_constant, call) = { let mut builder = ModuleBuilder::new(); let func = builder - .declare("func", FunctionType::new_endo(BOOL_T).into()) + .declare("func", Signature::new_endo(BOOL_T).into()) .unwrap(); let (load_constant, call) = { let mut builder = builder - .define_function("main", FunctionType::new(Type::EMPTY_TYPEROW, BOOL_T)) + .define_function("main", Signature::new(Type::EMPTY_TYPEROW, BOOL_T)) .unwrap(); let load_constant = builder.add_load_value(Value::true_val()); let [r] = builder diff --git a/hugr-core/src/builder/module.rs b/hugr-core/src/builder/module.rs index a57acc76b..d2f144e04 100644 --- a/hugr-core/src/builder/module.rs +++ b/hugr-core/src/builder/module.rs @@ -166,7 +166,7 @@ mod test { }, extension::{EMPTY_REG, PRELUDE_REGISTRY}, type_row, - types::FunctionType, + types::Signature, }; use super::*; @@ -177,7 +177,7 @@ mod test { let f_id = module_builder.declare( "main", - FunctionType::new(type_row![NAT], type_row![NAT]).into(), + Signature::new(type_row![NAT], type_row![NAT]).into(), )?; let mut f_build = module_builder.define_declaration(&f_id)?; @@ -200,7 +200,7 @@ mod test { let f_build = module_builder.define_function( "main", - FunctionType::new( + Signature::new( vec![qubit_state_type.get_alias_type()], vec![qubit_state_type.get_alias_type()], ), @@ -217,14 +217,10 @@ mod test { let build_result = { let mut module_builder = ModuleBuilder::new(); - let mut f_build = module_builder.define_function( - "main", - FunctionType::new(type_row![NAT], type_row![NAT, NAT]), - )?; - let local_build = f_build.define_function( - "local", - FunctionType::new(type_row![NAT], type_row![NAT, NAT]), - )?; + let mut f_build = module_builder + .define_function("main", Signature::new(type_row![NAT], type_row![NAT, NAT]))?; + let local_build = f_build + .define_function("local", Signature::new(type_row![NAT], type_row![NAT, NAT]))?; let [wire] = local_build.input_wires_arr(); let f_id = local_build.finish_with_outputs([wire, wire])?; diff --git a/hugr-core/src/builder/tail_loop.rs b/hugr-core/src/builder/tail_loop.rs index d993445e3..c7d5544e1 100644 --- a/hugr-core/src/builder/tail_loop.rs +++ b/hugr-core/src/builder/tail_loop.rs @@ -2,7 +2,7 @@ use crate::extension::ExtensionSet; use crate::ops; use crate::hugr::views::HugrView; -use crate::types::{FunctionType, TypeRow}; +use crate::types::{Signature, TypeRow}; use crate::{Hugr, Node}; use super::build_traits::SubContainer; @@ -21,7 +21,7 @@ impl + AsRef> TailLoopBuilder { loop_node: Node, tail_loop: &ops::TailLoop, ) -> Result { - let signature = FunctionType::new(tail_loop.body_input_row(), tail_loop.body_output_row()); + let signature = Signature::new(tail_loop.body_input_row(), tail_loop.body_output_row()); let dfg_build = DFGBuilder::create_with_io(base, loop_node, signature)?; Ok(TailLoopBuilder::from_dfg_builder(dfg_build)) @@ -102,6 +102,7 @@ mod test { hugr::ValidationError, ops::Value, type_row, + types::Signature, }; use super::*; @@ -128,7 +129,7 @@ mod test { let mut module_builder = ModuleBuilder::new(); let mut fbuild = module_builder.define_function( "main", - FunctionType::new(type_row![BIT], type_row![NAT]).with_extension_delta(PRELUDE_ID), + Signature::new(type_row![BIT], type_row![NAT]).with_extension_delta(PRELUDE_ID), )?; let _fdef = { let [b1] = fbuild diff --git a/hugr-core/src/extension.rs b/hugr-core/src/extension.rs index 0dfd9a13b..9f59c9106 100644 --- a/hugr-core/src/extension.rs +++ b/hugr-core/src/extension.rs @@ -16,8 +16,9 @@ use crate::ops::constant::{ValueName, ValueNameRef}; use crate::ops::custom::{ExtensionOp, OpaqueOp}; use crate::ops::{self, OpName, OpNameRef}; use crate::types::type_param::{TypeArg, TypeArgError, TypeParam}; +use crate::types::RowVariable; use crate::types::{check_typevar_decl, CustomType, Substitution, TypeBound, TypeName}; -use crate::types::{FunctionType, TypeNameRef}; +use crate::types::{Signature, TypeNameRef}; mod op_def; pub use op_def::{ @@ -155,8 +156,8 @@ pub enum SignatureError { #[error("Type variable {idx} was not declared ({num_decls} in scope)")] FreeTypeVar { idx: usize, num_decls: usize }, /// A row variable was found outside of a variable-length row - #[error("Expected a single type, but found row variable {idx}")] - RowVarWhereTypeExpected { idx: usize }, + #[error("Expected a single type, but found row variable {var}")] + RowVarWhereTypeExpected { var: RowVariable }, /// The result of the type application stored in a [Call] /// is not what we get by applying the type-args to the polymorphic function /// @@ -165,8 +166,8 @@ pub enum SignatureError { "Incorrect result of type application in Call - cached {cached} but expected {expected}" )] CallIncorrectlyAppliesType { - cached: FunctionType, - expected: FunctionType, + cached: Signature, + expected: Signature, }, /// The result of the type application stored in a [LoadFunction] /// is not what we get by applying the type-args to the polymorphic function @@ -176,8 +177,8 @@ pub enum SignatureError { "Incorrect result of type application in LoadFunction - cached {cached} but expected {expected}" )] LoadFunctionIncorrectlyAppliesType { - cached: FunctionType, - expected: FunctionType, + cached: Signature, + expected: Signature, }, } diff --git a/hugr-core/src/extension/declarative/signature.rs b/hugr-core/src/extension/declarative/signature.rs index df1aaab3b..d1479ae13 100644 --- a/hugr-core/src/extension/declarative/signature.rs +++ b/hugr-core/src/extension/declarative/signature.rs @@ -12,9 +12,9 @@ use serde::{Deserialize, Serialize}; use smol_str::SmolStr; use crate::extension::prelude::PRELUDE_ID; -use crate::extension::{CustomValidator, ExtensionSet, SignatureFunc, TypeDef}; +use crate::extension::{ExtensionSet, SignatureFunc, TypeDef}; use crate::types::type_param::TypeParam; -use crate::types::{CustomType, FunctionType, PolyFuncType, Type, TypeRow}; +use crate::types::{CustomType, FuncValueType, PolyFuncTypeRV, Type, TypeRowRV}; use crate::Extension; use super::{DeclarationContext, ExtensionDeclarationError}; @@ -41,7 +41,7 @@ impl SignatureDeclaration { op_params: &[TypeParam], ) -> Result { let make_type_row = - |v: &[SignaturePortDeclaration]| -> Result { + |v: &[SignaturePortDeclaration]| -> Result { let types = v .iter() .map(|port_decl| port_decl.make_types(ext, ctx, op_params)) @@ -50,16 +50,14 @@ impl SignatureDeclaration { Ok(types.into()) }; - let body = FunctionType { + let body = FuncValueType { input: make_type_row(&self.inputs)?, output: make_type_row(&self.outputs)?, extension_reqs: self.extensions.clone(), }; - let poly_func = PolyFuncType::new(op_params, body); - Ok(SignatureFunc::TypeScheme(CustomValidator::from_polyfunc( - poly_func, - ))) + let poly_func = PolyFuncTypeRV::new(op_params, body); + Ok(poly_func.into()) } } diff --git a/hugr-core/src/extension/op_def.rs b/hugr-core/src/extension/op_def.rs index 9b4f25569..61b6cd8b8 100644 --- a/hugr-core/src/extension/op_def.rs +++ b/hugr-core/src/extension/op_def.rs @@ -11,7 +11,7 @@ use super::{ use crate::ops::{OpName, OpNameRef}; use crate::types::type_param::{check_type_args, TypeArg, TypeParam}; -use crate::types::{FunctionType, PolyFuncType}; +use crate::types::{FuncValueType, PolyFuncType, PolyFuncTypeRV, Signature}; use crate::Hugr; /// Trait necessary for binary computations of OpDef signature @@ -24,7 +24,7 @@ pub trait CustomSignatureFunc: Send + Sync { arg_values: &[TypeArg], def: &'o OpDef, extension_registry: &ExtensionRegistry, - ) -> Result; + ) -> Result; /// The declared type parameters which require values in order for signature to /// be computed. fn static_params(&self) -> &[TypeParam]; @@ -34,7 +34,7 @@ pub trait CustomSignatureFunc: Send + Sync { pub trait SignatureFromArgs: Send + Sync { /// Compute signature of node given /// values for the type parameters. - fn compute_signature(&self, arg_values: &[TypeArg]) -> Result; + fn compute_signature(&self, arg_values: &[TypeArg]) -> Result; /// The declared type parameters which require values in order for signature to /// be computed. fn static_params(&self) -> &[TypeParam]; @@ -47,7 +47,7 @@ impl CustomSignatureFunc for T { arg_values: &[TypeArg], _def: &'o OpDef, _extension_registry: &ExtensionRegistry, - ) -> Result { + ) -> Result { SignatureFromArgs::compute_signature(self, arg_values) } @@ -57,7 +57,7 @@ impl CustomSignatureFunc for T { } } -/// Trait for validating type arguments to a PolyFuncType beyond conformation to +/// Trait for validating type arguments to a PolyFuncTypeRV beyond conformation to /// declared type parameter (which should have been checked beforehand). pub trait ValidateTypeArgs: Send + Sync { /// Validate the type arguments of node given @@ -71,7 +71,7 @@ pub trait ValidateTypeArgs: Send + Sync { ) -> Result<(), SignatureError>; } -/// Trait for validating type arguments to a PolyFuncType beyond conformation to +/// Trait for validating type arguments to a PolyFuncTypeRV beyond conformation to /// declared type parameter (which should have been checked beforehand), given just the arguments. pub trait ValidateJustArgs: Send + Sync { /// Validate the type arguments of node given @@ -114,30 +114,30 @@ pub trait CustomLowerFunc: Send + Sync { ) -> Option; } -/// Encode a signature as `PolyFuncType` but optionally allow validating type +/// Encode a signature as `PolyFuncTypeRV` but optionally allow validating type /// arguments via a custom binary. The binary cannot be serialized so will be /// lost over a serialization round-trip. #[derive(serde::Deserialize, serde::Serialize)] pub struct CustomValidator { #[serde(flatten)] - poly_func: PolyFuncType, + poly_func: PolyFuncTypeRV, #[serde(skip)] pub(crate) validate: Box, } impl CustomValidator { - /// Encode a signature using a `PolyFuncType` - pub fn from_polyfunc(poly_func: impl Into) -> Self { + /// Encode a signature using a `PolyFuncTypeRV` + pub fn from_polyfunc(poly_func: impl Into) -> Self { Self { poly_func: poly_func.into(), validate: Default::default(), } } - /// Encode a signature using a `PolyFuncType`, with a custom function for + /// Encode a signature using a `PolyFuncTypeRV`, with a custom function for /// validating type arguments before returning the signature. pub fn new_with_validator( - poly_func: impl Into, + poly_func: impl Into, validate: impl ValidateTypeArgs + 'static, ) -> Self { Self { @@ -153,10 +153,10 @@ pub enum SignatureFunc { // Note: except for serialization, we could have type schemes just implement the same // CustomSignatureFunc trait too, and replace this enum with Box. // However instead we treat all CustomFunc's as non-serializable. - /// A TypeScheme (polymorphic function type), with optional custom + /// A PolyFuncType (polymorphic function type), with optional custom /// validation for provided type arguments, #[serde(rename = "signature")] - TypeScheme(CustomValidator), + PolyFuncType(CustomValidator), #[serde(skip)] /// A custom binary which computes a polymorphic function type given values /// for its static type parameters. @@ -187,32 +187,44 @@ impl From for SignatureFunc { } impl From for SignatureFunc { - fn from(v: PolyFuncType) -> Self { - Self::TypeScheme(CustomValidator::from_polyfunc(v)) + fn from(value: PolyFuncType) -> Self { + Self::PolyFuncType(CustomValidator::from_polyfunc(value)) } } -impl From for SignatureFunc { - fn from(v: FunctionType) -> Self { - Self::TypeScheme(CustomValidator::from_polyfunc(v)) +impl From for SignatureFunc { + fn from(v: PolyFuncTypeRV) -> Self { + Self::PolyFuncType(CustomValidator::from_polyfunc(v)) + } +} + +impl From for SignatureFunc { + fn from(v: FuncValueType) -> Self { + Self::PolyFuncType(CustomValidator::from_polyfunc(v)) + } +} + +impl From for SignatureFunc { + fn from(v: Signature) -> Self { + Self::PolyFuncType(CustomValidator::from_polyfunc(FuncValueType::from(v))) } } impl From for SignatureFunc { fn from(v: CustomValidator) -> Self { - Self::TypeScheme(v) + Self::PolyFuncType(v) } } impl SignatureFunc { fn static_params(&self) -> &[TypeParam] { match self { - SignatureFunc::TypeScheme(ts) => ts.poly_func.params(), + SignatureFunc::PolyFuncType(ts) => ts.poly_func.params(), SignatureFunc::CustomFunc(func) => func.static_params(), } } - /// Compute the concrete signature ([FunctionType]). + /// Compute the concrete signature ([FuncValueType]). /// /// # Panics /// @@ -228,10 +240,10 @@ impl SignatureFunc { def: &OpDef, args: &[TypeArg], exts: &ExtensionRegistry, - ) -> Result { - let temp: PolyFuncType; + ) -> Result { + let temp: PolyFuncTypeRV; // to keep alive let (pf, args) = match &self { - SignatureFunc::TypeScheme(custom) => { + SignatureFunc::PolyFuncType(custom) => { custom.validate.validate(args, def, exts)?; (&custom.poly_func, args) } @@ -247,14 +259,16 @@ impl SignatureFunc { let mut res = pf.instantiate(args, exts)?; res.extension_reqs.insert(&def.extension); - Ok(res) + + // If there are any row variables left, this will fail with an error: + res.try_into() } } impl Debug for SignatureFunc { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { - Self::TypeScheme(ts) => ts.poly_func.fmt(f), + Self::PolyFuncType(ts) => ts.poly_func.fmt(f), Self::CustomFunc { .. } => f.write_str(""), } } @@ -328,9 +342,9 @@ impl OpDef { exts: &ExtensionRegistry, var_decls: &[TypeParam], ) -> Result<(), SignatureError> { - let temp: PolyFuncType; // to keep alive + let temp: PolyFuncTypeRV; // to keep alive let (pf, args) = match &self.signature_func { - SignatureFunc::TypeScheme(ts) => (&ts.poly_func, args), + SignatureFunc::PolyFuncType(ts) => (&ts.poly_func, args), SignatureFunc::CustomFunc(custom) => { let (static_args, other_args) = args.split_at(min(custom.static_params().len(), args.len())); @@ -354,7 +368,7 @@ impl OpDef { &self, args: &[TypeArg], exts: &ExtensionRegistry, - ) -> Result { + ) -> Result { self.signature_func.compute_signature(self, args, exts) } @@ -402,11 +416,11 @@ impl OpDef { pub(super) fn validate(&self, exts: &ExtensionRegistry) -> Result<(), SignatureError> { // TODO https://github.com/CQCL/hugr/issues/624 validate declared TypeParams // for both type scheme and custom binary - if let SignatureFunc::TypeScheme(ts) = &self.signature_func { + if let SignatureFunc::PolyFuncType(ts) = &self.signature_func { // The type scheme may contain row variables so be of variable length; // these will have to be substituted to fixed-length concrete types when // the OpDef is instantiated into an actual OpType. - ts.poly_func.validate_var_len(exts)?; + ts.poly_func.validate(exts)?; } Ok(()) } @@ -444,7 +458,7 @@ impl OpDef { impl Extension { /// Add an operation definition to the extension. Must be a type scheme - /// (defined by a [`PolyFuncType`]), a type scheme along with binary + /// (defined by a [`PolyFuncTypeRV`]), a type scheme along with binary /// validation for type arguments ([`CustomValidator`]), or a custom binary /// function for computing the signature given type arguments (`impl [CustomSignatureFunc]`). pub fn add_op( @@ -478,16 +492,15 @@ pub(super) mod test { use itertools::Itertools; use super::SignatureFromArgs; - use crate::builder::{endo_ft, DFGBuilder, Dataflow, DataflowHugr}; + use crate::builder::{endo_sig, DFGBuilder, Dataflow, DataflowHugr}; use crate::extension::op_def::{CustomValidator, LowerFunc, OpDef, SignatureFunc}; use crate::extension::prelude::USIZE_T; use crate::extension::{ExtensionRegistry, ExtensionSet, PRELUDE}; use crate::extension::{SignatureError, EMPTY_REG, PRELUDE_REGISTRY}; use crate::ops::{CustomOp, OpName}; use crate::std_extensions::collections::{EXTENSION, LIST_TYPENAME}; - use crate::types::type_param::TypeArgError; - use crate::types::Type; - use crate::types::{type_param::TypeParam, FunctionType, PolyFuncType, TypeArg, TypeBound}; + use crate::types::type_param::{TypeArgError, TypeParam}; + use crate::types::{PolyFuncTypeRV, Signature, Type, TypeArg, TypeBound, TypeRV}; use crate::{const_extension_ids, Extension}; const_extension_ids! { @@ -502,7 +515,7 @@ pub(super) mod test { assert!(op_def.constant_folder.is_none()); assert!(matches!( op_def.signature_func, - SignatureFunc::TypeScheme(_) + SignatureFunc::PolyFuncType(_) )); assert!(op_def .lower_funcs @@ -544,7 +557,7 @@ pub(super) mod test { // a compile error here. To fix: modify the fields matched on here, // maintaining the lack of `..` and, for each part that is // serializable, ensure we are checking it for equality below. - SignatureFunc::TypeScheme(CustomValidator { + SignatureFunc::PolyFuncType(CustomValidator { poly_func, validate: _, }) => Some(poly_func.clone()), @@ -583,7 +596,7 @@ pub(super) mod test { let list_of_var = Type::new_extension(list_def.instantiate(vec![TypeArg::new_var_use(0, TP)])?); const OP_NAME: OpName = OpName::new_inline("Reverse"); - let type_scheme = PolyFuncType::new(vec![TP], FunctionType::new_endo(vec![list_of_var])); + let type_scheme = PolyFuncTypeRV::new(vec![TP], Signature::new_endo(vec![list_of_var])); let def = e.add_op(OP_NAME, "desc".into(), type_scheme)?; def.add_lower_func(LowerFunc::FixedHugr { @@ -601,7 +614,7 @@ pub(super) mod test { let list_usize = Type::new_extension(list_def.instantiate(vec![TypeArg::Type { ty: USIZE_T }])?); - let mut dfg = DFGBuilder::new(endo_ft(vec![list_usize]))?; + let mut dfg = DFGBuilder::new(endo_sig(vec![list_usize]))?; let rev = dfg.add_dataflow_op( CustomOp::new_extension( e.instantiate_extension_op(&OP_NAME, vec![TypeArg::Type { ty: USIZE_T }], ®) @@ -616,7 +629,7 @@ pub(super) mod test { #[test] fn binary_polyfunc() -> Result<(), Box> { - // Test a custom binary `compute_signature` that returns a PolyFuncType + // Test a custom binary `compute_signature` that returns a PolyFuncTypeRV // where the latter declares more type params itself. In particular, // we should be able to substitute (external) type variables into the latter, // but not pass them into the former (custom binary function). @@ -625,7 +638,7 @@ pub(super) mod test { fn compute_signature( &self, arg_values: &[TypeArg], - ) -> Result { + ) -> Result { const TP: TypeParam = TypeParam::Type { b: TypeBound::Any }; let [TypeArg::BoundedNat { n }] = arg_values else { return Err(SignatureError::InvalidTypeArgs); @@ -634,9 +647,9 @@ pub(super) mod test { let tvs: Vec = (0..n) .map(|_| Type::new_var_use(0, TypeBound::Any)) .collect(); - Ok(PolyFuncType::new( + Ok(PolyFuncTypeRV::new( vec![TP.to_owned()], - FunctionType::new(tvs.clone(), vec![Type::new_tuple(tvs)]), + Signature::new(tvs.clone(), vec![Type::new_tuple(tvs)]), )) } @@ -654,7 +667,7 @@ pub(super) mod test { assert_eq!( def.compute_signature(&args, &PRELUDE_REGISTRY), Ok( - FunctionType::new(vec![USIZE_T; 3], vec![Type::new_tuple(vec![USIZE_T; 3])]) + Signature::new(vec![USIZE_T; 3], vec![Type::new_tuple(vec![USIZE_T; 3])]) .with_extension_delta(EXT_ID) ) ); @@ -667,7 +680,7 @@ pub(super) mod test { assert_eq!( def.compute_signature(&args, &PRELUDE_REGISTRY), Ok( - FunctionType::new(tyvars.clone(), vec![Type::new_tuple(tyvars)]) + Signature::new(tyvars.clone(), vec![Type::new_tuple(tyvars)]) .with_extension_delta(EXT_ID) ) ); @@ -705,15 +718,15 @@ pub(super) mod test { #[test] fn type_scheme_instantiate_var() -> Result<(), Box> { - // Check that we can instantiate a PolyFuncType-scheme with an (external) + // Check that we can instantiate a PolyFuncTypeRV-scheme with an (external) // type variable let mut e = Extension::new(EXT_ID); let def = e.add_op( "SimpleOp".into(), "".into(), - PolyFuncType::new( + PolyFuncTypeRV::new( vec![TypeBound::Any.into()], - FunctionType::new_endo(vec![Type::new_var_use(0, TypeBound::Any)]), + Signature::new_endo(vec![Type::new_var_use(0, TypeBound::Any)]), ), )?; let tv = Type::new_var_use(1, TypeBound::Eq); @@ -722,10 +735,10 @@ pub(super) mod test { def.validate_args(&args, &EMPTY_REG, &decls).unwrap(); assert_eq!( def.compute_signature(&args, &EMPTY_REG), - Ok(FunctionType::new_endo(vec![tv]).with_extension_delta(EXT_ID)) + Ok(Signature::new_endo(tv).with_extension_delta(EXT_ID)) ); // But not with an external row variable - let arg: TypeArg = Type::new_row_var_use(0, TypeBound::Eq).into(); + let arg: TypeArg = TypeRV::new_row_var_use(0, TypeBound::Eq).into(); assert_eq!( def.compute_signature(&[arg.clone()], &EMPTY_REG), Err(SignatureError::TypeArgMismatch( @@ -746,17 +759,17 @@ pub(super) mod test { let params: Vec = vec![TypeParam::Extensions]; let db_set = ExtensionSet::type_var(0); - let fun_ty = FunctionType::new_endo(vec![BOOL_T]).with_extension_delta(db_set); + let fun_ty = Signature::new_endo(BOOL_T).with_extension_delta(db_set); let def = e.add_op( "SimpleOp".into(), "".into(), - PolyFuncType::new(params.clone(), fun_ty), + PolyFuncTypeRV::new(params.clone(), fun_ty), )?; // Concrete extension set let es = ExtensionSet::singleton(&EXT_ID); - let exp_fun_ty = FunctionType::new_endo(vec![BOOL_T]).with_extension_delta(es.clone()); + let exp_fun_ty = Signature::new_endo(BOOL_T).with_extension_delta(es.clone()); let args = [TypeArg::Extensions { es }]; def.validate_args(&args, &PRELUDE_REGISTRY, ¶ms) @@ -777,7 +790,7 @@ pub(super) mod test { extension::{ op_def::LowerFunc, CustomValidator, ExtensionId, ExtensionSet, OpDef, SignatureFunc, }, - types::PolyFuncType, + types::PolyFuncTypeRV, }; impl Arbitrary for SignatureFunc { @@ -787,8 +800,8 @@ pub(super) mod test { // TODO there is also SignatureFunc::CustomFunc, but for now // this is not serialized. When it is, we should generate // examples here . - any::() - .prop_map(|x| SignatureFunc::TypeScheme(CustomValidator::from_polyfunc(x))) + any::() + .prop_map(|x| SignatureFunc::PolyFuncType(CustomValidator::from_polyfunc(x))) .boxed() } } diff --git a/hugr-core/src/extension/prelude.rs b/hugr-core/src/extension/prelude.rs index a17ba4259..12a61f19c 100644 --- a/hugr-core/src/extension/prelude.rs +++ b/hugr-core/src/extension/prelude.rs @@ -4,14 +4,14 @@ use lazy_static::lazy_static; use crate::ops::constant::{CustomCheckFailure, ValueName}; use crate::ops::{CustomOp, OpName}; -use crate::types::{SumType, TypeName}; +use crate::types::{FuncValueType, SumType, TypeName}; use crate::{ extension::{ExtensionId, TypeDefBound}, ops::constant::CustomConst, type_row, types::{ type_param::{TypeArg, TypeParam}, - CustomType, FunctionType, PolyFuncType, Type, TypeBound, + CustomType, PolyFuncTypeRV, Signature, Type, TypeBound, }, Extension, }; @@ -21,7 +21,7 @@ struct ArrayOpCustom; const MAX: &[TypeParam; 1] = &[TypeParam::max_nat()]; impl SignatureFromArgs for ArrayOpCustom { - fn compute_signature(&self, arg_values: &[TypeArg]) -> Result { + fn compute_signature(&self, arg_values: &[TypeArg]) -> Result { let [TypeArg::BoundedNat { n }] = *arg_values else { return Err(SignatureError::InvalidTypeArgs); }; @@ -30,9 +30,9 @@ impl SignatureFromArgs for ArrayOpCustom { let var_arg_row = vec![elem_ty_var.clone(); n as usize]; let other_row = vec![array_type(TypeArg::BoundedNat { n }, elem_ty_var.clone())]; - Ok(PolyFuncType::new( + Ok(PolyFuncTypeRV::new( vec![TypeBound::Any.into()], - FunctionType::new(var_arg_row, other_row), + FuncValueType::new(var_arg_row, other_row), )) } @@ -43,7 +43,7 @@ impl SignatureFromArgs for ArrayOpCustom { struct GenericOpCustom; impl SignatureFromArgs for GenericOpCustom { - fn compute_signature(&self, arg_values: &[TypeArg]) -> Result { + fn compute_signature(&self, arg_values: &[TypeArg]) -> Result { let [arg0, arg1] = arg_values else { return Err(SignatureError::InvalidTypeArgs); }; @@ -67,7 +67,7 @@ impl SignatureFromArgs for GenericOpCustom { }; outs.push(ty.clone()); } - Ok(PolyFuncType::new(vec![], FunctionType::new(inps, outs))) + Ok(FuncValueType::new(inps, outs).into()) } fn static_params(&self) -> &[TypeParam] { @@ -106,7 +106,7 @@ lazy_static! { prelude.add_op( PRINT_OP_ID, "Print the string to standard output".to_string(), - FunctionType::new(type_row![STRING_TYPE], type_row![]), + Signature::new(type_row![STRING_TYPE], type_row![]), ) .unwrap(); prelude.add_type( @@ -268,7 +268,7 @@ pub const ERROR_TYPE_NAME: TypeName = TypeName::new_inline("error"); /// Return a Sum type with the first variant as the given type and the second an Error. pub fn sum_with_error(ty: Type) -> SumType { - SumType::new([vec![ty], vec![ERROR_TYPE]]) + SumType::new([ty, ERROR_TYPE]) } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] @@ -402,7 +402,7 @@ impl CustomConst for ConstExternalSymbol { #[cfg(test)] mod test { use crate::{ - builder::{endo_ft, inout_ft, DFGBuilder, Dataflow, DataflowHugr}, + builder::{endo_sig, inout_sig, DFGBuilder, Dataflow, DataflowHugr}, utils::test_quantum_extension::cx_gate, Hugr, Wire, }; @@ -412,7 +412,7 @@ mod test { #[test] /// Test building a HUGR involving a new_array operation. fn test_new_array() { - let mut b = DFGBuilder::new(inout_ft( + let mut b = DFGBuilder::new(inout_sig( vec![QB_T, QB_T], array_type(TypeArg::BoundedNat { n: 2 }, QB_T), )) @@ -452,7 +452,7 @@ mod test { assert!(error_val.equal_consts(&ConstError::new(2, "my message"))); assert!(!error_val.equal_consts(&ConstError::new(3, "my message"))); - let mut b = DFGBuilder::new(endo_ft(type_row![])).unwrap(); + let mut b = DFGBuilder::new(endo_sig(type_row![])).unwrap(); let err = b.add_load_value(error_val); @@ -486,7 +486,7 @@ mod test { ) .unwrap(); - let mut b = DFGBuilder::new(endo_ft(type_row![QB_T, QB_T])).unwrap(); + let mut b = DFGBuilder::new(endo_sig(type_row![QB_T, QB_T])).unwrap(); let [q0, q1] = b.input_wires_arr(); let [q0, q1] = b .add_dataflow_op(cx_gate(), [q0, q1]) @@ -524,7 +524,7 @@ mod test { #[test] /// Test print operation fn test_print() { - let mut b: DFGBuilder = DFGBuilder::new(endo_ft(vec![])).unwrap(); + let mut b: DFGBuilder = DFGBuilder::new(endo_sig(vec![])).unwrap(); let greeting: ConstString = ConstString::new("Hello, world!".into()); let greeting_out: Wire = b.add_load_value(greeting); let print_op = PRELUDE diff --git a/hugr-core/src/extension/simple_op.rs b/hugr-core/src/extension/simple_op.rs index c77ed5edc..4d3703f21 100644 --- a/hugr-core/src/extension/simple_op.rs +++ b/hugr-core/src/extension/simple_op.rs @@ -240,7 +240,7 @@ impl From for OpType { #[cfg(test)] mod test { - use crate::{const_extension_ids, type_row, types::FunctionType}; + use crate::{const_extension_ids, type_row, types::Signature}; use super::*; use lazy_static::lazy_static; @@ -253,7 +253,7 @@ mod test { impl MakeOpDef for DummyEnum { fn signature(&self) -> SignatureFunc { - FunctionType::new_endo(type_row![]).into() + Signature::new_endo(type_row![]).into() } fn from_def(_op_def: &OpDef) -> Result { diff --git a/hugr-core/src/extension/type_def.rs b/hugr-core/src/extension/type_def.rs index 5ca9e2f7c..9e0c8753b 100644 --- a/hugr-core/src/extension/type_def.rs +++ b/hugr-core/src/extension/type_def.rs @@ -167,7 +167,7 @@ mod test { use crate::extension::SignatureError; use crate::std_extensions::arithmetic::float_types::FLOAT64_TYPE; use crate::types::type_param::{TypeArg, TypeArgError, TypeParam}; - use crate::types::{FunctionType, Type, TypeBound}; + use crate::types::{Signature, Type, TypeBound}; use super::{TypeDef, TypeDefBound}; @@ -184,12 +184,12 @@ mod test { }; let typ = Type::new_extension( def.instantiate(vec![TypeArg::Type { - ty: Type::new_function(FunctionType::new(vec![], vec![])), + ty: Type::new_function(Signature::new(vec![], vec![])), }]) .unwrap(), ); assert_eq!(typ.least_upper_bound(), TypeBound::Copyable); - let typ2 = Type::new_extension(def.instantiate([TypeArg::Type { ty: USIZE_T }]).unwrap()); + let typ2 = Type::new_extension(def.instantiate([USIZE_T.into()]).unwrap()); assert_eq!(typ2.least_upper_bound(), TypeBound::Eq); // And some bad arguments...firstly, wrong kind of TypeArg: diff --git a/hugr-core/src/hugr.rs b/hugr-core/src/hugr.rs index 7b16c6ff3..fcf358bc2 100644 --- a/hugr-core/src/hugr.rs +++ b/hugr-core/src/hugr.rs @@ -304,7 +304,7 @@ mod test { use crate::extension::{ ExtensionId, ExtensionSet, EMPTY_REG, PRELUDE_REGISTRY, TO_BE_INFERRED, }; - use crate::types::{FunctionType, Type}; + use crate::types::{Signature, Type}; use crate::{const_extension_ids, ops, test_file, type_row}; use rstest::rstest; @@ -435,9 +435,9 @@ mod test { } fn build_ext_dfg(parent: ExtensionSet) -> (Hugr, Node) { - let ty = Type::new_function(FunctionType::new_endo(type_row![])); + let ty = Type::new_function(Signature::new_endo(type_row![])); let mut h = Hugr::new(ops::DFG { - signature: FunctionType::new_endo(ty.clone()).with_extension_delta(parent.clone()), + signature: Signature::new_endo(ty.clone()).with_extension_delta(parent.clone()), }); let root = h.root(); let mid = add_inliftout(&mut h, root, ty); @@ -492,7 +492,7 @@ mod test { #[case] success: bool, #[case] result: impl IntoIterator, ) { - let ty = Type::new_function(FunctionType::new_endo(type_row![])); + let ty = Type::new_function(Signature::new_endo(type_row![])); let grandparent = ExtensionSet::from_iter(grandparent); let result = ExtensionSet::from_iter(result); let root_ty = ops::Conditional { @@ -505,7 +505,7 @@ mod test { let p = h.add_node_with_parent( h.root(), ops::Case { - signature: FunctionType::new_endo(ty.clone()) + signature: Signature::new_endo(ty.clone()) .with_extension_delta(ExtensionSet::from_iter(parent)), }, ); @@ -516,7 +516,7 @@ mod test { if success { assert!(inf_res.is_ok()); let expected_p = ops::Case { - signature: FunctionType::new_endo(ty).with_extension_delta(result.clone()), + signature: Signature::new_endo(ty).with_extension_delta(result.clone()), }; let mut expected = backup; expected.replace_op(p, expected_p).unwrap(); diff --git a/hugr-core/src/hugr/hugrmut.rs b/hugr-core/src/hugr/hugrmut.rs index 08d852249..42b8964a5 100644 --- a/hugr-core/src/hugr/hugrmut.rs +++ b/hugr-core/src/hugr/hugrmut.rs @@ -510,7 +510,7 @@ mod test { extension::PRELUDE_REGISTRY, macros::type_row, ops::{self, dataflow::IOTrait, Noop}, - types::{FunctionType, Type}, + types::{Signature, Type}, }; use super::*; @@ -529,7 +529,7 @@ mod test { module, ops::FuncDefn { name: "main".into(), - signature: FunctionType::new(type_row![NAT], type_row![NAT, NAT]).into(), + signature: Signature::new(type_row![NAT], type_row![NAT, NAT]).into(), }, ); diff --git a/hugr-core/src/hugr/rewrite/consts.rs b/hugr-core/src/hugr/rewrite/consts.rs index fde420bb6..05122af46 100644 --- a/hugr-core/src/hugr/rewrite/consts.rs +++ b/hugr-core/src/hugr/rewrite/consts.rs @@ -121,14 +121,14 @@ mod test { }, ops::{handle::NodeHandle, MakeTuple, Value}, type_row, - types::FunctionType, + types::Signature, }; #[test] fn test_const_remove() -> Result<(), Box> { let mut build = ModuleBuilder::new(); let con_node = build.add_constant(Value::extension(ConstUsize::new(2))); - let mut dfg_build = build.define_function("main", FunctionType::new_endo(type_row![]))?; + let mut dfg_build = build.define_function("main", Signature::new_endo(type_row![]))?; let load_1 = dfg_build.load_const(&con_node); let load_2 = dfg_build.load_const(&con_node); let tup = dfg_build.add_dataflow_op( diff --git a/hugr-core/src/hugr/rewrite/inline_dfg.rs b/hugr-core/src/hugr/rewrite/inline_dfg.rs index 37f3a1cee..281479b21 100644 --- a/hugr-core/src/hugr/rewrite/inline_dfg.rs +++ b/hugr-core/src/hugr/rewrite/inline_dfg.rs @@ -133,7 +133,7 @@ mod test { use rstest::rstest; use crate::builder::{ - endo_ft, inout_ft, Container, DFGBuilder, Dataflow, DataflowHugr, DataflowSubContainer, + endo_sig, inout_sig, Container, DFGBuilder, Dataflow, DataflowHugr, DataflowSubContainer, SubContainer, }; use crate::extension::prelude::QB_T; @@ -145,7 +145,7 @@ mod test { use crate::std_extensions::arithmetic::float_types; use crate::std_extensions::arithmetic::int_ops::{self, IntOpDef}; use crate::std_extensions::arithmetic::int_types::{self, ConstInt}; - use crate::types::FunctionType; + use crate::types::Signature; use crate::utils::test_quantum_extension; use crate::{type_row, Direction, HugrView, Node, Port}; use crate::{Hugr, Wire}; @@ -175,7 +175,7 @@ mod test { .unwrap(); let int_ty = &int_types::INT_TYPES[6]; - let mut outer = DFGBuilder::new(inout_ft(vec![int_ty.clone(); 2], vec![int_ty.clone()]))?; + let mut outer = DFGBuilder::new(inout_sig(vec![int_ty.clone(); 2], vec![int_ty.clone()]))?; let [a, b] = outer.input_wires_arr(); fn make_const + AsRef>( d: &mut DFGBuilder, @@ -245,13 +245,13 @@ mod test { #[test] fn permutation() -> Result<(), Box> { - let mut h = DFGBuilder::new(endo_ft(type_row![QB_T, QB_T]))?; + let mut h = DFGBuilder::new(endo_sig(type_row![QB_T, QB_T]))?; let [p, q] = h.input_wires_arr(); let [p_h] = h .add_dataflow_op(test_quantum_extension::h_gate(), [p])? .outputs_arr(); let swap = { - let swap = h.dfg_builder(FunctionType::new_endo(type_row![QB_T, QB_T]), [p_h, q])?; + let swap = h.dfg_builder(Signature::new_endo(type_row![QB_T, QB_T]), [p_h, q])?; let [a, b] = swap.input_wires_arr(); swap.finish_with_outputs([b, a])? }; @@ -340,11 +340,11 @@ mod test { PRELUDE.to_owned(), ]) .unwrap(); - let mut outer = DFGBuilder::new(endo_ft(type_row![QB_T, QB_T]))?; + let mut outer = DFGBuilder::new(endo_sig(type_row![QB_T, QB_T]))?; let [a, b] = outer.input_wires_arr(); let h_a = outer.add_dataflow_op(test_quantum_extension::h_gate(), [a])?; let h_b = outer.add_dataflow_op(test_quantum_extension::h_gate(), [b])?; - let mut inner = outer.dfg_builder(endo_ft(QB_T), h_b.outputs())?; + let mut inner = outer.dfg_builder(endo_sig(QB_T), h_b.outputs())?; let [i] = inner.input_wires_arr(); let f = inner.add_load_value(float_types::ConstF64::new(1.0)); inner.add_other_wire(inner.input().node(), f.node()); diff --git a/hugr-core/src/hugr/rewrite/outline_cfg.rs b/hugr-core/src/hugr/rewrite/outline_cfg.rs index 1d2ce2ee5..1543be973 100644 --- a/hugr-core/src/hugr/rewrite/outline_cfg.rs +++ b/hugr-core/src/hugr/rewrite/outline_cfg.rs @@ -257,7 +257,7 @@ mod test { use crate::hugr::HugrMut; use crate::ops::constant::Value; use crate::ops::handle::{BasicBlockID, CfgID, ConstID, NodeHandle}; - use crate::types::FunctionType; + use crate::types::Signature; use crate::{type_row, Hugr, HugrView, Node}; use cool_asserts::assert_matches; use itertools::Itertools; @@ -278,7 +278,7 @@ mod test { } impl CondThenLoopCfg { fn new() -> Result { - let block_ty = FunctionType::new_endo(USIZE_T); + let block_ty = Signature::new_endo(USIZE_T); let mut cfg_builder = CFGBuilder::new(block_ty.clone())?; let pred_const = cfg_builder.add_constant(Value::unit_sum(0, 2).expect("0 < 2")); let const_unit = cfg_builder.add_constant(Value::unary_unit_sum()); @@ -311,7 +311,7 @@ mod test { let head = id_block(&mut cfg_builder)?; cfg_builder.branch(&merge, 0, &head)?; let tail = n_identity( - cfg_builder.simple_block_builder(FunctionType::new_endo(USIZE_T), 2)?, + cfg_builder.simple_block_builder(Signature::new_endo(USIZE_T), 2)?, &pred_const, )?; cfg_builder.branch(&tail, 1, &head)?; @@ -441,7 +441,7 @@ mod test { let mut fbuild = module_builder .define_function( "main", - FunctionType::new(type_row![USIZE_T], type_row![USIZE_T]), + Signature::new(type_row![USIZE_T], type_row![USIZE_T]), ) .unwrap(); let [i1] = fbuild.input_wires_arr(); diff --git a/hugr-core/src/hugr/rewrite/replace.rs b/hugr-core/src/hugr/rewrite/replace.rs index 72bd9e1b9..bbee8c7e3 100644 --- a/hugr-core/src/hugr/rewrite/replace.rs +++ b/hugr-core/src/hugr/rewrite/replace.rs @@ -446,7 +446,7 @@ mod test { use itertools::Itertools; use crate::builder::{ - endo_ft, BuildError, CFGBuilder, Container, DFGBuilder, Dataflow, DataflowHugr, + endo_sig, BuildError, CFGBuilder, Container, DFGBuilder, Dataflow, DataflowHugr, DataflowSubContainer, HugrBuilder, SubContainer, }; use crate::extension::prelude::{BOOL_T, USIZE_T}; @@ -459,7 +459,7 @@ mod test { use crate::ops::handle::{BasicBlockID, ConstID, NodeHandle}; use crate::ops::{self, Case, DataflowBlock, OpTag, OpType, DFG}; use crate::std_extensions::collections; - use crate::types::{FunctionType, Type, TypeArg, TypeRow}; + use crate::types::{Signature, Type, TypeArg, TypeRow}; use crate::utils::depth; use crate::{type_row, Direction, Hugr, HugrView, OutgoingPort}; @@ -488,7 +488,7 @@ mod test { let just_list = TypeRow::from(vec![listy.clone()]); let intermed = TypeRow::from(vec![listy.clone(), USIZE_T]); - let mut cfg = CFGBuilder::new(endo_ft(just_list.clone()))?; + let mut cfg = CFGBuilder::new(endo_sig(just_list.clone()))?; let pred_const = cfg.add_constant(ops::Value::unary_unit_sum()); @@ -518,7 +518,7 @@ mod test { // Replacement: one BB with two DFGs inside. // Use Hugr rather than Builder because DFGs must be empty (not even Input/Output). let mut replacement = Hugr::new(ops::CFG { - signature: FunctionType::new_endo(just_list.clone()), + signature: Signature::new_endo(just_list.clone()), }); let r_bb = replacement.add_node_with_parent( replacement.root(), @@ -532,17 +532,14 @@ mod test { let r_df1 = replacement.add_node_with_parent( r_bb, DFG { - signature: FunctionType::new( - vec![listy.clone()], - simple_unary_plus(intermed.clone()), - ) - .with_extension_delta(collections::EXTENSION_NAME), + signature: Signature::new(vec![listy.clone()], simple_unary_plus(intermed.clone())) + .with_extension_delta(collections::EXTENSION_NAME), }, ); let r_df2 = replacement.add_node_with_parent( r_bb, DFG { - signature: FunctionType::new(intermed, simple_unary_plus(just_list.clone())) + signature: Signature::new(intermed, simple_unary_plus(just_list.clone())) .with_extension_delta(collections::EXTENSION_NAME), }, ); @@ -644,7 +641,7 @@ mod test { #[test] fn test_invalid() -> Result<(), Box> { - let utou = FunctionType::new_endo(vec![USIZE_T]); + let utou = Signature::new_endo(vec![USIZE_T]); let mk_op = |s| { CustomOp::new_opaque(OpaqueOp::new( ExtensionId::new("unknown_ext").unwrap(), @@ -654,7 +651,7 @@ mod test { utou.clone(), )) }; - let mut h = DFGBuilder::new(FunctionType::new( + let mut h = DFGBuilder::new(Signature::new( type_row![USIZE_T, BOOL_T], type_row![USIZE_T], ))?; diff --git a/hugr-core/src/hugr/rewrite/simple_replace.rs b/hugr-core/src/hugr/rewrite/simple_replace.rs index fb12ff344..a1cd8d57a 100644 --- a/hugr-core/src/hugr/rewrite/simple_replace.rs +++ b/hugr-core/src/hugr/rewrite/simple_replace.rs @@ -219,7 +219,7 @@ pub(in crate::hugr::rewrite) mod test { use std::collections::{HashMap, HashSet}; use crate::builder::{ - endo_ft, inout_ft, BuildError, Container, DFGBuilder, Dataflow, DataflowHugr, + endo_sig, inout_sig, BuildError, Container, DFGBuilder, Dataflow, DataflowHugr, DataflowSubContainer, HugrBuilder, ModuleBuilder, }; use crate::extension::prelude::BOOL_T; @@ -233,7 +233,7 @@ pub(in crate::hugr::rewrite) mod test { use crate::std_extensions::logic::test::and_op; use crate::std_extensions::logic::NotOp; use crate::type_row; - use crate::types::{FunctionType, Type}; + use crate::types::{Signature, Type}; use crate::utils::test_quantum_extension::{cx_gate, h_gate, EXTENSION_ID}; use crate::{IncomingPort, Node}; @@ -256,7 +256,7 @@ pub(in crate::hugr::rewrite) mod test { let just_q: ExtensionSet = EXTENSION_ID.into(); let mut func_builder = module_builder.define_function( "main", - FunctionType::new_endo(type_row![QB, QB, QB]).with_extension_delta(just_q.clone()), + Signature::new_endo(type_row![QB, QB, QB]).with_extension_delta(just_q.clone()), )?; let [qb0, qb1, qb2] = func_builder.input_wires_arr(); @@ -292,7 +292,7 @@ pub(in crate::hugr::rewrite) mod test { /// ┤ H ├┤ X ├ /// └───┘└───┘ fn make_dfg_hugr() -> Result { - let mut dfg_builder = DFGBuilder::new(endo_ft(type_row![QB, QB]))?; + let mut dfg_builder = DFGBuilder::new(endo_sig(type_row![QB, QB]))?; let [wire0, wire1] = dfg_builder.input_wires_arr(); let wire2 = dfg_builder.add_dataflow_op(h_gate(), vec![wire0])?; let wire3 = dfg_builder.add_dataflow_op(h_gate(), vec![wire1])?; @@ -312,7 +312,7 @@ pub(in crate::hugr::rewrite) mod test { /// ┤ H ├ /// └───┘ fn make_dfg_hugr2() -> Result { - let mut dfg_builder = DFGBuilder::new(endo_ft(type_row![QB, QB]))?; + let mut dfg_builder = DFGBuilder::new(endo_sig(type_row![QB, QB]))?; let [wire0, wire1] = dfg_builder.input_wires_arr(); let wire2 = dfg_builder.add_dataflow_op(h_gate(), vec![wire1])?; @@ -341,7 +341,7 @@ pub(in crate::hugr::rewrite) mod test { pub(in crate::hugr::rewrite) fn dfg_hugr_copy_bools() -> (Hugr, Vec) { fn build() -> Result<(Hugr, Vec), BuildError> { let mut dfg_builder = - DFGBuilder::new(inout_ft(type_row![BOOL_T], type_row![BOOL_T, BOOL_T]))?; + DFGBuilder::new(inout_sig(type_row![BOOL_T], type_row![BOOL_T, BOOL_T]))?; let [b] = dfg_builder.input_wires_arr(); let not_inp = dfg_builder.add_dataflow_op(NotOp, vec![b])?; @@ -518,7 +518,7 @@ pub(in crate::hugr::rewrite) mod test { #[test] fn test_replace_cx_cross() { let q_row: Vec = vec![QB, QB]; - let mut builder = DFGBuilder::new(endo_ft(q_row)).unwrap(); + let mut builder = DFGBuilder::new(endo_sig(q_row)).unwrap(); let mut circ = builder.as_circuit(builder.input_wires()); circ.append(cx_gate(), [0, 1]).unwrap(); circ.append(cx_gate(), [1, 0]).unwrap(); @@ -576,7 +576,7 @@ pub(in crate::hugr::rewrite) mod test { let one_bit = type_row![BOOL_T]; let two_bit = type_row![BOOL_T, BOOL_T]; - let mut builder = DFGBuilder::new(endo_ft(one_bit.clone())).unwrap(); + let mut builder = DFGBuilder::new(endo_sig(one_bit.clone())).unwrap(); let inw = builder.input_wires().exactly_one().unwrap(); let outw = builder .add_dataflow_op(and_op(), [inw, inw]) @@ -585,7 +585,7 @@ pub(in crate::hugr::rewrite) mod test { let [input, _] = builder.io(); let mut h = builder.finish_hugr_with_outputs(outw, &EMPTY_REG).unwrap(); - let mut builder = DFGBuilder::new(inout_ft(two_bit, one_bit)).unwrap(); + let mut builder = DFGBuilder::new(inout_sig(two_bit, one_bit)).unwrap(); let inw = builder.input_wires(); let outw = builder.add_dataflow_op(and_op(), inw).unwrap().outputs(); let [repl_input, repl_output] = builder.io(); @@ -633,10 +633,7 @@ pub(in crate::hugr::rewrite) mod test { let [_input, output] = hugr.get_io(hugr.root()).unwrap(); let replacement = { - let b = DFGBuilder::new(FunctionType::new( - type_row![BOOL_T], - type_row![BOOL_T, BOOL_T], - ))?; + let b = DFGBuilder::new(Signature::new(type_row![BOOL_T], type_row![BOOL_T, BOOL_T]))?; let [w] = b.input_wires_arr(); b.finish_prelude_hugr_with_outputs([w, w])? }; diff --git a/hugr-core/src/hugr/serialize/test.rs b/hugr-core/src/hugr/serialize/test.rs index 5a5a0f69e..1822aa346 100644 --- a/hugr-core/src/hugr/serialize/test.rs +++ b/hugr-core/src/hugr/serialize/test.rs @@ -1,6 +1,6 @@ use super::*; use crate::builder::{ - endo_ft, inout_ft, test::closed_dfg_root_hugr, Container, DFGBuilder, Dataflow, DataflowHugr, + endo_sig, inout_sig, test::closed_dfg_root_hugr, Container, DFGBuilder, Dataflow, DataflowHugr, DataflowSubContainer, HugrBuilder, ModuleBuilder, }; use crate::extension::prelude::{BOOL_T, PRELUDE_ID, QB_T, USIZE_T}; @@ -13,8 +13,10 @@ use crate::std_extensions::arithmetic::float_types::FLOAT64_TYPE; use crate::std_extensions::arithmetic::int_ops::INT_OPS_REGISTRY; use crate::std_extensions::arithmetic::int_types::{int_custom_type, ConstInt, INT_TYPES}; use crate::std_extensions::logic::NotOp; +use crate::types::type_param::TypeParam; use crate::types::{ - type_param::TypeParam, FunctionType, PolyFuncType, SumType, Type, TypeArg, TypeBound, + FuncValueType, PolyFuncType, PolyFuncTypeRV, Signature, SumType, Type, TypeArg, TypeBound, + TypeRV, }; use crate::{type_row, OutgoingPort}; @@ -31,9 +33,9 @@ const QB: Type = crate::extension::prelude::QB_T; /// Version 1 of the Testing HUGR serialization format, see `testing_hugr.py`. #[derive(Serialize, Deserialize, PartialEq, Debug, Default)] struct SerTestingV1 { - typ: Option, + typ: Option, sum_type: Option, - poly_func_type: Option, + poly_func_type: Option, value: Option, optype: Option, op_def: Option, @@ -86,13 +88,27 @@ macro_rules! impl_sertesting_from { }; } -impl_sertesting_from!(crate::types::Type, typ); +impl_sertesting_from!(crate::types::TypeRV, typ); impl_sertesting_from!(crate::types::SumType, sum_type); -impl_sertesting_from!(crate::types::PolyFuncType, poly_func_type); +impl_sertesting_from!(crate::types::PolyFuncTypeRV, poly_func_type); impl_sertesting_from!(crate::ops::Value, value); impl_sertesting_from!(NodeSer, optype); impl_sertesting_from!(SimpleOpDef, op_def); +impl From for TestingModel { + fn from(v: PolyFuncType) -> Self { + let v: PolyFuncTypeRV = v.into(); + v.into() + } +} + +impl From for TestingModel { + fn from(v: Type) -> Self { + let t: TypeRV = v.into(); + t.into() + } +} + #[test] fn empty_hugr_serialize() { check_hugr_roundtrip(&Hugr::default(), true); @@ -198,7 +214,7 @@ fn gen_optype(g: &MultiPortGraph, node: portgraph::NodeIndex) -> OpType { let outputs = g.num_outputs(node); match (inputs == 0, outputs == 0) { (false, false) => DFG { - signature: FunctionType::new(vec![NAT; inputs - 1], vec![NAT; outputs - 1]), + signature: Signature::new(vec![NAT; inputs - 1], vec![NAT; outputs - 1]), } .into(), (true, false) => Input::new(vec![NAT; outputs - 1]).into(), @@ -252,7 +268,7 @@ fn weighted_hugr_ser() { let t_row = vec![Type::new_sum([type_row![NAT], type_row![QB]])]; let mut f_build = module_builder - .define_function("main", FunctionType::new(t_row.clone(), t_row)) + .define_function("main", Signature::new(t_row.clone(), t_row)) .unwrap(); let outputs = f_build @@ -281,7 +297,7 @@ fn weighted_hugr_ser() { #[test] fn dfg_roundtrip() -> Result<(), Box> { let tp: Vec = vec![BOOL_T; 2]; - let mut dfg = DFGBuilder::new(FunctionType::new(tp.clone(), tp))?; + let mut dfg = DFGBuilder::new(Signature::new(tp.clone(), tp))?; let mut params: [_; 2] = dfg.input_wires_arr(); for p in params.iter_mut() { *p = dfg @@ -298,7 +314,7 @@ fn dfg_roundtrip() -> Result<(), Box> { #[test] fn opaque_ops() -> Result<(), Box> { let tp: Vec = vec![BOOL_T; 1]; - let mut dfg = DFGBuilder::new(endo_ft(tp))?; + let mut dfg = DFGBuilder::new(endo_sig(tp))?; let [wire] = dfg.input_wires_arr(); // Add an extension operation @@ -320,8 +336,8 @@ fn opaque_ops() -> Result<(), Box> { #[test] fn function_type() -> Result<(), Box> { - let fn_ty = Type::new_function(FunctionType::new_endo(type_row![BOOL_T])); - let mut bldr = DFGBuilder::new(FunctionType::new_endo(vec![fn_ty.clone()]))?; + let fn_ty = Type::new_function(Signature::new_endo(type_row![BOOL_T])); + let mut bldr = DFGBuilder::new(Signature::new_endo(vec![fn_ty.clone()]))?; let op = bldr.add_dataflow_op(Noop { ty: fn_ty }, bldr.input_wires())?; let h = bldr.finish_prelude_hugr_with_outputs(op.outputs())?; @@ -331,7 +347,7 @@ fn function_type() -> Result<(), Box> { #[test] fn hierarchy_order() -> Result<(), Box> { - let mut hugr = closed_dfg_root_hugr(FunctionType::new(vec![QB], vec![QB])); + let mut hugr = closed_dfg_root_hugr(Signature::new(vec![QB], vec![QB])); let [old_in, out] = hugr.get_io(hugr.root()).unwrap(); hugr.connect(old_in, 0, out, 0); @@ -351,7 +367,7 @@ fn hierarchy_order() -> Result<(), Box> { #[test] fn constants_roundtrip() -> Result<(), Box> { - let mut builder = DFGBuilder::new(inout_ft(vec![], INT_TYPES[4].clone())).unwrap(); + let mut builder = DFGBuilder::new(inout_sig(vec![], INT_TYPES[4].clone())).unwrap(); let w = builder.add_load_value(ConstInt::new_s(4, -2).unwrap()); let hugr = builder.finish_hugr_with_outputs([w], &INT_OPS_REGISTRY)?; @@ -365,8 +381,7 @@ fn constants_roundtrip() -> Result<(), Box> { #[test] fn serialize_types_roundtrip() { - let g: Type = Type::new_function(FunctionType::new_endo(vec![])); - + let g: Type = Type::new_function(Signature::new_endo(vec![])); check_testing_roundtrip(g.clone()); // A Simple tuple @@ -374,7 +389,7 @@ fn serialize_types_roundtrip() { check_testing_roundtrip(t); // A Classic sum - let t = Type::new_sum([type_row![USIZE_T], type_row![FLOAT64_TYPE]]); + let t = TypeRV::new_sum([type_row![USIZE_T], type_row![FLOAT64_TYPE]]); check_testing_roundtrip(t); let t = Type::new_unit_sum(4); @@ -389,7 +404,7 @@ fn serialize_types_roundtrip() { #[case(Type::new_var_use(2, TypeBound::Copyable))] #[case(Type::new_tuple(type_row![BOOL_T,QB_T]))] #[case(Type::new_sum([type_row![BOOL_T,QB_T], type_row![Type::new_unit_sum(4)]]))] -#[case(Type::new_function(FunctionType::new_endo(type_row![QB_T,BOOL_T,USIZE_T])))] +#[case(Type::new_function(Signature::new_endo(type_row![QB_T,BOOL_T,USIZE_T])))] fn roundtrip_type(#[case] typ: Type) { check_testing_roundtrip(typ); } @@ -416,37 +431,50 @@ fn roundtrip_value(#[case] value: Value) { fn polyfunctype1() -> PolyFuncType { let mut extension_set = ExtensionSet::new(); extension_set.insert_type_var(1); - let function_type = FunctionType::new_endo(type_row![]).with_extension_delta(extension_set); + let function_type = Signature::new_endo(type_row![]).with_extension_delta(extension_set); PolyFuncType::new([TypeParam::max_nat(), TypeParam::Extensions], function_type) } -fn polyfunctype2() -> PolyFuncType { - let tv0 = Type::new_row_var_use(0, TypeBound::Any); - let tv1 = Type::new_row_var_use(1, TypeBound::Eq); +fn polyfunctype2() -> PolyFuncTypeRV { + let tv0 = TypeRV::new_row_var_use(0, TypeBound::Any); + let tv1 = TypeRV::new_row_var_use(1, TypeBound::Eq); let params = [TypeBound::Any, TypeBound::Eq].map(TypeParam::new_list); let inputs = vec![ - Type::new_function(FunctionType::new(tv0.clone(), tv1.clone())), + TypeRV::new_function(FuncValueType::new(tv0.clone(), tv1.clone())), tv0, ]; - let res = PolyFuncType::new(params, FunctionType::new(inputs, tv1)); + let res = PolyFuncTypeRV::new(params, FuncValueType::new(inputs, tv1)); // Just check we've got the arguments the right way round // (not that it really matters for the serialization schema we have) - res.validate_var_len(&EMPTY_REG).unwrap(); + res.validate(&EMPTY_REG).unwrap(); res } #[rstest] -#[case(FunctionType::new_endo(type_row![]).into())] +#[case(Signature::new_endo(type_row![]).into())] #[case(polyfunctype1())] -#[case(PolyFuncType::new([TypeParam::Opaque { ty: int_custom_type(TypeArg::BoundedNat { n: 1 }) }], FunctionType::new_endo(type_row![Type::new_var_use(0, TypeBound::Copyable)])))] -#[case(PolyFuncType::new([TypeBound::Eq.into()], FunctionType::new_endo(type_row![Type::new_var_use(0, TypeBound::Eq)])))] -#[case(PolyFuncType::new([TypeParam::new_list(TypeBound::Any)], FunctionType::new_endo(type_row![])))] -#[case(PolyFuncType::new([TypeParam::Tuple { params: [TypeBound::Any.into(), TypeParam::bounded_nat(2.try_into().unwrap())].into() }], FunctionType::new_endo(type_row![])))] +#[case(PolyFuncType::new([TypeParam::Opaque { ty: int_custom_type(TypeArg::BoundedNat { n: 1 }) }], Signature::new_endo(type_row![Type::new_var_use(0, TypeBound::Copyable)])))] +#[case(PolyFuncType::new([TypeBound::Eq.into()], Signature::new_endo(type_row![Type::new_var_use(0, TypeBound::Eq)])))] +#[case(PolyFuncType::new([TypeParam::new_list(TypeBound::Any)], Signature::new_endo(type_row![])))] +#[case(PolyFuncType::new([TypeParam::Tuple { params: [TypeBound::Any.into(), TypeParam::bounded_nat(2.try_into().unwrap())].into() }], Signature::new_endo(type_row![])))] #[case(PolyFuncType::new( [TypeParam::new_list(TypeBound::Any)], - FunctionType::new_endo(Type::new_tuple(Type::new_row_var_use(0, TypeBound::Any)))))] + Signature::new_endo(Type::new_tuple(TypeRV::new_row_var_use(0, TypeBound::Any)))))] +fn roundtrip_polyfunctype_fixedlen(#[case] poly_func_type: PolyFuncType) { + check_testing_roundtrip(poly_func_type) +} + +#[rstest] +#[case(FuncValueType::new_endo(type_row![]).into())] +#[case(PolyFuncTypeRV::new([TypeParam::Opaque { ty: int_custom_type(TypeArg::BoundedNat { n: 1 }) }], FuncValueType::new_endo(type_row![Type::new_var_use(0, TypeBound::Copyable)])))] +#[case(PolyFuncTypeRV::new([TypeBound::Eq.into()], FuncValueType::new_endo(type_row![Type::new_var_use(0, TypeBound::Eq)])))] +#[case(PolyFuncTypeRV::new([TypeParam::new_list(TypeBound::Any)], FuncValueType::new_endo(type_row![])))] +#[case(PolyFuncTypeRV::new([TypeParam::Tuple { params: [TypeBound::Any.into(), TypeParam::bounded_nat(2.try_into().unwrap())].into() }], FuncValueType::new_endo(type_row![])))] +#[case(PolyFuncTypeRV::new( + [TypeParam::new_list(TypeBound::Any)], + FuncValueType::new_endo(TypeRV::new_row_var_use(0, TypeBound::Any))))] #[case(polyfunctype2())] -fn roundtrip_polyfunctype(#[case] poly_func_type: PolyFuncType) { +fn roundtrip_polyfunctype_varlen(#[case] poly_func_type: PolyFuncTypeRV) { check_testing_roundtrip(poly_func_type) } @@ -459,9 +487,9 @@ fn roundtrip_polyfunctype(#[case] poly_func_type: PolyFuncType) { #[case(ops::Const::new(Value::false_val()))] #[case(ops::Const::new(Value::function(crate::builder::test::simple_dfg_hugr()).unwrap()))] #[case(ops::Input::new(type_row![Type::new_var_use(3,TypeBound::Eq)]))] -#[case(ops::Output::new(vec![Type::new_function(FunctionType::new_endo(type_row![]))]))] +#[case(ops::Output::new(vec![Type::new_function(FuncValueType::new_endo(type_row![]))]))] #[case(ops::Call::try_new(polyfunctype1(), [TypeArg::BoundedNat{n: 1}, TypeArg::Extensions{ es: ExtensionSet::singleton(&PRELUDE_ID)} ], &EMPTY_REG).unwrap())] -#[case(ops::CallIndirect { signature : FunctionType::new_endo(type_row![BOOL_T]) })] +#[case(ops::CallIndirect { signature : Signature::new_endo(type_row![BOOL_T]) })] fn roundtrip_optype(#[case] optype: impl Into + std::fmt::Debug) { check_testing_roundtrip(NodeSer { parent: portgraph::NodeIndex::new(0).into(), @@ -484,7 +512,7 @@ mod proptest { use super::check_testing_roundtrip; use super::{NodeSer, SimpleOpDef}; use crate::ops::{OpType, Value}; - use crate::types::{PolyFuncType, Type}; + use crate::types::{PolyFuncTypeRV, Type}; use proptest::prelude::*; impl Arbitrary for NodeSer { @@ -507,7 +535,7 @@ mod proptest { } #[test] - fn prop_roundtrip_poly_func_type(t: PolyFuncType) { + fn prop_roundtrip_poly_func_type(t: PolyFuncTypeRV) { check_testing_roundtrip(t) } diff --git a/hugr-core/src/hugr/validate.rs b/hugr-core/src/hugr/validate.rs index 1eeaecabd..7c978262e 100644 --- a/hugr-core/src/hugr/validate.rs +++ b/hugr-core/src/hugr/validate.rs @@ -16,7 +16,7 @@ use crate::ops::custom::{resolve_opaque_op, CustomOp, CustomOpError}; use crate::ops::validate::{ChildrenEdgeData, ChildrenValidationError, EdgeValidationError}; use crate::ops::{FuncDefn, OpParent, OpTag, OpTrait, OpType, ValidateOp}; use crate::types::type_param::TypeParam; -use crate::types::{EdgeKind, FunctionType}; +use crate::types::{EdgeKind, Signature}; use crate::{Direction, Hugr, Node, Port}; use super::views::{HierarchyView, HugrView, SiblingGraph}; @@ -65,7 +65,7 @@ impl Hugr { return Err(ValidationError::ExtensionsNotInferred { node: parent }); } let parent_extensions = match parent_op.inner_function_type() { - Some(FunctionType { extension_reqs, .. }) => extension_reqs, + Some(Signature { extension_reqs, .. }) => extension_reqs, None => match parent_op.tag() { OpTag::Cfg | OpTag::Conditional => parent_op.extension_delta(), // ModuleRoot holds but does not execute its children, so allow any extensions @@ -199,19 +199,6 @@ impl<'a, 'b> ValidationContext<'a, 'b> { } } - // Secondly, check that the node signature does not contain any row variables. - // (We do this here so it's before we try indexing into the ports of any nodes). - op_type - .dataflow_signature() - .as_ref() - .and_then(FunctionType::find_rowvar) - .map_or(Ok(()), |(idx, _)| { - Err(ValidationError::SignatureError { - node, - cause: SignatureError::RowVarWhereTypeExpected { idx }, - }) - })?; - // Thirdly that the node has correct children self.validate_children(node, op_type)?; @@ -309,14 +296,11 @@ impl<'a, 'b> ValidationContext<'a, 'b> { var_decls: &[TypeParam], ) -> Result<(), SignatureError> { match &port_kind { - EdgeKind::Value(ty) => ty.validate(false, self.extension_registry, var_decls), + EdgeKind::Value(ty) => ty.validate(self.extension_registry, var_decls), // Static edges must *not* refer to type variables declared by enclosing FuncDefns - // as these are only types at runtime. (Note the choice of `allow_row_vars` as `false` is arbitrary here.) - EdgeKind::Const(ty) => ty.validate(false, self.extension_registry, &[]), - // Allow function "value" to have unknown arity. A Call node will have to provide - // TypeArgs that produce a known arity, but a LoadFunction might pass the function - // value ("function pointer") around without knowing how to call it. - EdgeKind::Function(pf) => pf.validate_var_len(self.extension_registry), + // as these are only types at runtime. + EdgeKind::Const(ty) => ty.validate(self.extension_registry, &[]), + EdgeKind::Function(pf) => pf.validate(self.extension_registry), _ => Ok(()), } } diff --git a/hugr-core/src/hugr/validate/test.rs b/hugr-core/src/hugr/validate/test.rs index 2be635e29..fbc847f1c 100644 --- a/hugr-core/src/hugr/validate/test.rs +++ b/hugr-core/src/hugr/validate/test.rs @@ -2,12 +2,11 @@ use std::fs::File; use std::io::BufReader; use cool_asserts::assert_matches; -use rstest::rstest; use super::*; use crate::builder::test::closed_dfg_root_hugr; use crate::builder::{ - inout_ft, BuildError, Container, DFGBuilder, Dataflow, DataflowHugr, DataflowSubContainer, + inout_sig, BuildError, Container, DFGBuilder, Dataflow, DataflowHugr, DataflowSubContainer, FunctionBuilder, HugrBuilder, ModuleBuilder, SubContainer, }; use crate::extension::prelude::{BOOL_T, PRELUDE, PRELUDE_ID, QB_T, USIZE_T}; @@ -21,7 +20,10 @@ use crate::ops::{self, Noop, OpType, Value}; use crate::std_extensions::logic::test::{and_op, or_op}; use crate::std_extensions::logic::{self, NotOp}; use crate::types::type_param::{TypeArg, TypeArgError}; -use crate::types::{CustomType, FunctionType, PolyFuncType, Type, TypeBound, TypeRow}; +use crate::types::{ + CustomType, FuncValueType, PolyFuncType, PolyFuncTypeRV, Signature, Type, TypeBound, TypeRV, + TypeRow, +}; use crate::{const_extension_ids, test_file, type_row, Direction, IncomingPort, Node}; const NAT: Type = crate::extension::prelude::USIZE_T; @@ -32,7 +34,7 @@ const NAT: Type = crate::extension::prelude::USIZE_T; fn make_simple_hugr(copies: usize) -> (Hugr, Node) { let def_op: OpType = ops::FuncDefn { name: "main".into(), - signature: FunctionType::new(type_row![BOOL_T], vec![BOOL_T; copies]).into(), + signature: Signature::new(type_row![BOOL_T], vec![BOOL_T; copies]).into(), } .into(); @@ -106,7 +108,7 @@ fn leaf_root() { #[test] fn dfg_root() { let dfg_op: OpType = ops::DFG { - signature: FunctionType::new_endo(type_row![BOOL_T]), + signature: Signature::new_endo(type_row![BOOL_T]), } .into(); @@ -135,7 +137,7 @@ fn children_restrictions() { .unwrap(); // Add a definition without children - let def_sig = FunctionType::new(type_row![BOOL_T], type_row![BOOL_T, BOOL_T]); + let def_sig = Signature::new(type_row![BOOL_T], type_row![BOOL_T, BOOL_T]); let new_def = b.add_node_with_parent( root, ops::FuncDefn { @@ -208,7 +210,7 @@ fn df_children_restrictions() { #[test] fn test_ext_edge() { let mut h = closed_dfg_root_hugr( - FunctionType::new(type_row![BOOL_T, BOOL_T], type_row![BOOL_T]) + Signature::new(type_row![BOOL_T, BOOL_T], type_row![BOOL_T]) .with_extension_delta(TO_BE_INFERRED), ); let [input, output] = h.get_io(h.root()).unwrap(); @@ -217,8 +219,7 @@ fn test_ext_edge() { let sub_dfg = h.add_node_with_parent( h.root(), ops::DFG { - signature: FunctionType::new_endo(type_row![BOOL_T]) - .with_extension_delta(TO_BE_INFERRED), + signature: Signature::new_endo(type_row![BOOL_T]).with_extension_delta(TO_BE_INFERRED), }, ); // this Xor has its 2nd input unconnected @@ -253,14 +254,11 @@ fn test_ext_edge() { #[test] fn no_ext_edge_into_func() -> Result<(), Box> { - let b2b = FunctionType::new_endo(BOOL_T); - let mut h = DFGBuilder::new(FunctionType::new(BOOL_T, Type::new_function(b2b.clone())))?; + let b2b = Signature::new_endo(BOOL_T); + let mut h = DFGBuilder::new(Signature::new(BOOL_T, Type::new_function(b2b.clone())))?; let [input] = h.input_wires_arr(); - let mut dfg = h.dfg_builder( - FunctionType::new(vec![], Type::new_function(b2b.clone())), - [], - )?; + let mut dfg = h.dfg_builder(Signature::new(vec![], Type::new_function(b2b.clone())), [])?; let mut func = dfg.define_function("AndWithOuter", b2b.clone())?; let [fn_input] = func.input_wires_arr(); let and_op = func.add_dataflow_op(and_op(), [fn_input, input])?; // 'ext' edge @@ -286,7 +284,7 @@ fn no_ext_edge_into_func() -> Result<(), Box> { #[test] fn test_local_const() { let mut h = - closed_dfg_root_hugr(FunctionType::new_endo(BOOL_T).with_extension_delta(TO_BE_INFERRED)); + closed_dfg_root_hugr(Signature::new_endo(BOOL_T).with_extension_delta(TO_BE_INFERRED)); let [input, output] = h.get_io(h.root()).unwrap(); let and = h.add_node_with_parent(h.root(), and_op()); h.connect(input, 0, and, 0); @@ -318,10 +316,7 @@ fn test_local_const() { #[test] fn dfg_with_cycles() { - let mut h = closed_dfg_root_hugr(FunctionType::new( - type_row![BOOL_T, BOOL_T], - type_row![BOOL_T], - )); + let mut h = closed_dfg_root_hugr(Signature::new(type_row![BOOL_T, BOOL_T], type_row![BOOL_T])); let [input, output] = h.get_io(h.root()).unwrap(); let or = h.add_node_with_parent(h.root(), or_op()); let not1 = h.add_node_with_parent(h.root(), NotOp); @@ -343,7 +338,7 @@ fn identity_hugr_with_type(t: Type) -> (Hugr, Node) { b.root(), ops::FuncDefn { name: "main".into(), - signature: FunctionType::new(row.clone(), row.clone()).into(), + signature: Signature::new(row.clone(), row.clone()).into(), }, ); @@ -466,7 +461,7 @@ fn typevars_declared() -> Result<(), Box> { "myfunc", PolyFuncType::new( [TypeBound::Any.into()], - FunctionType::new_endo(vec![Type::new_var_use(0, TypeBound::Any)]), + Signature::new_endo(vec![Type::new_var_use(0, TypeBound::Any)]), ), )?; let [w] = f.input_wires_arr(); @@ -476,7 +471,7 @@ fn typevars_declared() -> Result<(), Box> { "myfunc", PolyFuncType::new( [TypeBound::Any.into()], - FunctionType::new_endo(vec![Type::new_var_use(1, TypeBound::Any)]), + Signature::new_endo(vec![Type::new_var_use(1, TypeBound::Any)]), ), )?; let [w] = f.input_wires_arr(); @@ -486,7 +481,7 @@ fn typevars_declared() -> Result<(), Box> { "myfunc", PolyFuncType::new( [TypeBound::Any.into()], - FunctionType::new_endo(vec![Type::new_var_use(1, TypeBound::Copyable)]), + Signature::new_endo(vec![Type::new_var_use(1, TypeBound::Copyable)]), ), )?; let [w] = f.input_wires_arr(); @@ -504,12 +499,12 @@ fn nested_typevars() -> Result<(), Box> { "outer", PolyFuncType::new( [OUTER_BOUND.into()], - FunctionType::new_endo(vec![Type::new_var_use(0, TypeBound::Any)]), + Signature::new_endo(vec![Type::new_var_use(0, TypeBound::Any)]), ), )?; let inner = outer.define_function( "inner", - PolyFuncType::new([INNER_BOUND.into()], FunctionType::new_endo(vec![t])), + PolyFuncType::new([INNER_BOUND.into()], Signature::new_endo(vec![t])), )?; let [w] = inner.input_wires_arr(); inner.finish_with_outputs([w])?; @@ -550,7 +545,7 @@ fn no_polymorphic_consts() -> Result<(), Box> { "myfunc", PolyFuncType::new( [BOUND], - FunctionType::new(vec![], vec![list_of_var.clone()]) + Signature::new(vec![], vec![list_of_var.clone()]) .with_extension_delta(collections::EXTENSION_NAME), ), )?; @@ -577,24 +572,24 @@ pub(crate) fn extension_with_eval_parallel() -> Extension { let rowp = TypeParam::new_list(TypeBound::Any); let mut e = Extension::new(EXT_ID); - let inputs = Type::new_row_var_use(0, TypeBound::Any); - let outputs = Type::new_row_var_use(1, TypeBound::Any); - let evaled_fn = Type::new_function(FunctionType::new(inputs.clone(), outputs.clone())); - let pf = PolyFuncType::new( + let inputs = TypeRV::new_row_var_use(0, TypeBound::Any); + let outputs = TypeRV::new_row_var_use(1, TypeBound::Any); + let evaled_fn = TypeRV::new_function(FuncValueType::new(inputs.clone(), outputs.clone())); + let pf = PolyFuncTypeRV::new( [rowp.clone(), rowp.clone()], - FunctionType::new(vec![evaled_fn, inputs], outputs), + FuncValueType::new(vec![evaled_fn, inputs], outputs), ); e.add_op("eval".into(), "".into(), pf).unwrap(); - let rv = |idx| Type::new_row_var_use(idx, TypeBound::Any); - let pf = PolyFuncType::new( + let rv = |idx| TypeRV::new_row_var_use(idx, TypeBound::Any); + let pf = PolyFuncTypeRV::new( [rowp.clone(), rowp.clone(), rowp.clone(), rowp.clone()], - FunctionType::new( + Signature::new( vec![ - Type::new_function(FunctionType::new(rv(0), rv(2))), - Type::new_function(FunctionType::new(rv(1), rv(3))), + Type::new_function(FuncValueType::new(rv(0), rv(2))), + Type::new_function(FuncValueType::new(rv(1), rv(3))), ], - Type::new_function(FunctionType::new(vec![rv(0), rv(1)], vec![rv(2), rv(3)])), + Type::new_function(FuncValueType::new(vec![rv(0), rv(1)], vec![rv(2), rv(3)])), ), ); e.add_op("parallel".into(), "".into(), pf).unwrap(); @@ -608,9 +603,9 @@ fn instantiate_row_variables() -> Result<(), Box> { vec![TypeArg::Type { ty: USIZE_T }; i].into() } let e = extension_with_eval_parallel(); - let mut dfb = DFGBuilder::new(inout_ft( + let mut dfb = DFGBuilder::new(inout_sig( vec![ - Type::new_function(FunctionType::new(USIZE_T, vec![USIZE_T, USIZE_T])), + Type::new_function(Signature::new(USIZE_T, vec![USIZE_T, USIZE_T])), USIZE_T, ], // inputs: function + its argument vec![USIZE_T; 4], // outputs (*2^2, three calls) @@ -634,42 +629,39 @@ fn instantiate_row_variables() -> Result<(), Box> { Ok(()) } -fn seq1ty(t: Type) -> TypeArg { +fn seq1ty(t: TypeRV) -> TypeArg { TypeArg::Sequence { elems: vec![t.into()], } } #[test] -fn inner_row_variables() -> Result<(), Box> { +fn row_variables() -> Result<(), Box> { let e = extension_with_eval_parallel(); - let tv = Type::new_row_var_use(0, TypeBound::Any); - let inner_ft = Type::new_function(FunctionType::new_endo(tv.clone())); - let ft_usz = Type::new_function(FunctionType::new_endo(vec![tv.clone(), USIZE_T])); + let tv = TypeRV::new_row_var_use(0, TypeBound::Any); + let inner_ft = Type::new_function(FuncValueType::new_endo(tv.clone())); + let ft_usz = Type::new_function(FuncValueType::new_endo(vec![tv.clone(), USIZE_T.into()])); let mut fb = FunctionBuilder::new( "id", PolyFuncType::new( [TypeParam::new_list(TypeBound::Any)], - FunctionType::new(inner_ft.clone(), ft_usz).with_extension_delta(e.name.clone()), + Signature::new(inner_ft.clone(), ft_usz).with_extension_delta(e.name.clone()), ), )?; // All the wires here are carrying higher-order Function values let [func_arg] = fb.input_wires_arr(); let [id_usz] = { - let bldr = fb.define_function("id_usz", FunctionType::new_endo(USIZE_T))?; + let bldr = fb.define_function("id_usz", Signature::new_endo(USIZE_T))?; let vals = bldr.input_wires(); let [inner_def] = bldr.finish_with_outputs(vals)?.outputs_arr(); - let loadf = LoadFunction::try_new( - FunctionType::new_endo(USIZE_T).into(), - [], - &PRELUDE_REGISTRY, - ) - .unwrap(); + let loadf = + LoadFunction::try_new(Signature::new_endo(USIZE_T).into(), [], &PRELUDE_REGISTRY) + .unwrap(); fb.add_dataflow_op(loadf, [inner_def])?.outputs_arr() }; let par = e.instantiate_extension_op( "parallel", - [tv.clone(), USIZE_T, tv.clone(), USIZE_T].map(seq1ty), + [tv.clone(), USIZE_T.into(), tv.clone(), USIZE_T.into()].map(seq1ty), &PRELUDE_REGISTRY, )?; let par_func = fb.add_dataflow_op(par, [func_arg, id_usz])?; @@ -680,60 +672,6 @@ fn inner_row_variables() -> Result<(), Box> { Ok(()) } -#[rstest] -#[case(false)] -#[case(true)] -fn no_outer_row_variables(#[case] connect: bool) -> Result<(), Box> { - let e = extension_with_eval_parallel(); - let tv = Type::new_row_var_use(0, TypeBound::Copyable); - let fun_ty = Type::new_function(FunctionType::new(USIZE_T, tv.clone())); - let results = if connect { vec![tv.clone()] } else { vec![] }; - let mut fb = Hugr::new(FuncDefn { - name: "bad_eval".to_string(), - signature: PolyFuncType::new( - [TypeParam::new_list(TypeBound::Copyable)], - FunctionType::new(fun_ty.clone(), results.clone()), - ), - }); - let inp = fb.add_node_with_parent( - fb.root(), - ops::Input { - types: fun_ty.into(), - }, - ); - let out = fb.add_node_with_parent( - fb.root(), - ops::Output { - types: results.into(), - }, - ); - let cst = fb.add_node_with_parent( - fb.root(), - ops::Const::new(crate::extension::prelude::ConstUsize::new(5).into()), - ); - let i = fb.add_node_with_parent(fb.root(), ops::LoadConstant { datatype: USIZE_T }); - fb.connect(cst, 0, i, 0); - - let ev = fb.add_node_with_parent( - fb.root(), - e.instantiate_extension_op("eval", [seq1ty(USIZE_T), seq1ty(tv)], &PRELUDE_REGISTRY)?, - ); - fb.connect(inp, 0, ev, 0); - fb.connect(i, 0, ev, 1); - if connect { - fb.connect(ev, 0, out, 0); - } - let reg = ExtensionRegistry::try_new([PRELUDE.to_owned(), e]).unwrap(); - assert_matches!( - fb.validate(®).unwrap_err(), - ValidationError::SignatureError { - node, - cause: SignatureError::RowVarWhereTypeExpected { idx: 0 } - } => assert!([ev, out].contains(&node)) - ); - Ok(()) -} - #[test] fn test_polymorphic_call() -> Result<(), Box> { let mut e = Extension::new(EXT_ID); @@ -744,7 +682,7 @@ fn test_polymorphic_call() -> Result<(), Box> { TypeBound::Any.into(), ]; let evaled_fn = Type::new_function( - FunctionType::new( + Signature::new( Type::new_var_use(0, TypeBound::Any), Type::new_var_use(2, TypeBound::Any), ) @@ -755,9 +693,9 @@ fn test_polymorphic_call() -> Result<(), Box> { e.add_op( "eval".into(), "".into(), - PolyFuncType::new( + PolyFuncTypeRV::new( params.clone(), - FunctionType::new( + Signature::new( vec![evaled_fn, Type::new_var_use(0, TypeBound::Any)], Type::new_var_use(2, TypeBound::Any), ) @@ -766,12 +704,12 @@ fn test_polymorphic_call() -> Result<(), Box> { )?; fn utou(e: impl Into) -> Type { - Type::new_function(FunctionType::new_endo(USIZE_T).with_extension_delta(e.into())) + Type::new_function(Signature::new_endo(USIZE_T).with_extension_delta(e.into())) } let int_pair = Type::new_tuple(type_row![USIZE_T; 2]); // Root DFG: applies a function int--PRELUDE-->int to each element of a pair of two ints - let mut d = DFGBuilder::new(inout_ft( + let mut d = DFGBuilder::new(inout_sig( vec![utou(PRELUDE_ID), int_pair.clone()], vec![int_pair.clone()], ))?; @@ -782,7 +720,7 @@ fn test_polymorphic_call() -> Result<(), Box> { "two_ints", PolyFuncType::new( vec![TypeParam::Extensions], - FunctionType::new(vec![utou(es.clone()), int_pair.clone()], int_pair.clone()) + Signature::new(vec![utou(es.clone()), int_pair.clone()], int_pair.clone()) .with_extension_delta(EXT_ID) .with_extension_delta(es.clone()), ), @@ -825,7 +763,7 @@ fn test_polymorphic_call() -> Result<(), Box> { )?; let h = d.finish_hugr_with_outputs(call.outputs(), ®)?; let call_ty = h.get_optype(call.node()).dataflow_signature().unwrap(); - let exp_fun_ty = FunctionType::new(vec![utou(PRELUDE_ID), int_pair.clone()], int_pair) + let exp_fun_ty = Signature::new(vec![utou(PRELUDE_ID), int_pair.clone()], int_pair) .with_extension_delta(EXT_ID) .with_extension_delta(PRELUDE_ID); assert_eq!(call_ty, exp_fun_ty); @@ -839,12 +777,12 @@ fn test_polymorphic_load() -> Result<(), Box> { "id", PolyFuncType::new( vec![TypeBound::Any.into()], - FunctionType::new_endo(vec![Type::new_var_use(0, TypeBound::Any)]), + Signature::new_endo(vec![Type::new_var_use(0, TypeBound::Any)]), ), )?; - let sig = FunctionType::new( + let sig = Signature::new( vec![], - vec![Type::new_function(FunctionType::new_endo(vec![USIZE_T]))], + vec![Type::new_function(Signature::new_endo(vec![USIZE_T]))], ); let mut f = m.define_function("main", sig)?; let l = f.load_func(&id, &[USIZE_T.into()], &PRELUDE_REGISTRY)?; @@ -869,7 +807,7 @@ fn cfg_children_restrictions() { b.replace_op( copy, ops::CFG { - signature: FunctionType::new(type_row![BOOL_T], type_row![BOOL_T]), + signature: Signature::new(type_row![BOOL_T], type_row![BOOL_T]), }, ) .unwrap(); @@ -932,7 +870,7 @@ fn cfg_children_restrictions() { b.replace_op( cfg, ops::CFG { - signature: FunctionType::new(type_row![QB_T], type_row![BOOL_T]), + signature: Signature::new(type_row![QB_T], type_row![BOOL_T]), }, ) .unwrap(); @@ -970,14 +908,14 @@ fn cfg_children_restrictions() { fn cfg_connections() -> Result<(), Box> { use crate::builder::CFGBuilder; - let mut hugr = CFGBuilder::new(FunctionType::new_endo(USIZE_T))?; + let mut hugr = CFGBuilder::new(Signature::new_endo(USIZE_T))?; let unary_pred = hugr.add_constant(Value::unary_unit_sum()); let mut entry = hugr.simple_entry_builder_exts(type_row![USIZE_T], 1, ExtensionSet::new())?; let p = entry.load_const(&unary_pred); let ins = entry.input_wires(); let entry = entry.finish_with_outputs(p, ins)?; - let mut middle = hugr.simple_block_builder(FunctionType::new_endo(USIZE_T), 1)?; + let mut middle = hugr.simple_block_builder(Signature::new_endo(USIZE_T), 1)?; let p = middle.load_const(&unary_pred); let ins = middle.input_wires(); let middle = middle.finish_with_outputs(p, ins)?; @@ -1020,6 +958,7 @@ fn cfg_entry_io_bug() -> Result<(), Box> { #[cfg(feature = "extension_inference")] mod extension_tests { use self::ops::handle::{BasicBlockID, TailLoopID}; + use rstest::rstest; use super::*; use crate::builder::handle::Outputs; @@ -1035,17 +974,16 @@ mod extension_tests { #[rstest] #[case::d1(|signature| ops::DFG {signature}.into())] - #[case::f1(|ft: FunctionType| ops::FuncDefn {name: "foo".to_string(), signature: ft.into()}.into())] + #[case::f1(|sig: Signature| ops::FuncDefn {name: "foo".to_string(), signature: sig.into()}.into())] #[case::c1(|signature| ops::Case {signature}.into())] fn parent_extension_mismatch( - #[case] parent_f: impl Fn(FunctionType) -> OpType, + #[case] parent_f: impl Fn(Signature) -> OpType, #[values(ExtensionSet::new(), XA.into())] parent_extensions: ExtensionSet, ) { // Child graph adds extension "XB", but the parent (in all cases) // declares a different delta, causing a mismatch. - let parent = parent_f( - FunctionType::new_endo(USIZE_T).with_extension_delta(parent_extensions.clone()), - ); + let parent = + parent_f(Signature::new_endo(USIZE_T).with_extension_delta(parent_extensions.clone())); let mut hugr = Hugr::new(parent); let input = hugr.add_node_with_parent( @@ -1093,7 +1031,7 @@ mod extension_tests { #[case] success: bool, ) -> Result<(), BuildError> { let mut cfg = CFGBuilder::new( - FunctionType::new_endo(USIZE_T).with_extension_delta(parent_extensions.clone()), + Signature::new_endo(USIZE_T).with_extension_delta(parent_extensions.clone()), )?; let mut bb = cfg.simple_entry_builder_exts(USIZE_T.into(), 1, XB)?; let pred = bb.add_load_value(Value::unary_unit_sum()); @@ -1143,8 +1081,7 @@ mod extension_tests { let case = hugr.add_node_with_parent( hugr.root(), ops::Case { - signature: FunctionType::new_endo(USIZE_T) - .with_extension_delta(case_exts.clone()), + signature: Signature::new_endo(USIZE_T).with_extension_delta(case_exts.clone()), }, ); diff --git a/hugr-core/src/hugr/views.rs b/hugr-core/src/hugr/views.rs index 9be9faf89..6a52f33f0 100644 --- a/hugr-core/src/hugr/views.rs +++ b/hugr-core/src/hugr/views.rs @@ -32,8 +32,7 @@ use crate::extension::ExtensionRegistry; use crate::ops::handle::NodeHandle; use crate::ops::{OpParent, OpTag, OpTrait, OpType}; -use crate::types::{EdgeKind, FunctionType}; -use crate::types::{PolyFuncType, Type}; +use crate::types::{EdgeKind, PolyFuncType, Signature, Type}; use crate::{Direction, IncomingPort, Node, OutgoingPort, Port}; use itertools::Either; @@ -333,8 +332,8 @@ pub trait HugrView: HugrInternals { /// graph. Otherwise, returns `None`. /// /// In contrast to [`poly_func_type`][HugrView::poly_func_type], this - /// method always return a concrete [`FunctionType`]. - fn inner_function_type(&self) -> Option { + /// method always return a concrete [`Signature`]. + fn inner_function_type(&self) -> Option { self.root_type().inner_function_type() } @@ -431,7 +430,7 @@ pub trait HugrView: HugrInternals { /// Get the "signature" (incoming and outgoing types) of a node, non-Value /// kind ports will be missing. - fn signature(&self, node: Node) -> Option { + fn signature(&self, node: Node) -> Option { self.get_optype(node).dataflow_signature() } diff --git a/hugr-core/src/hugr/views/descendants.rs b/hugr-core/src/hugr/views/descendants.rs index 8b5afa2f1..83a7d6687 100644 --- a/hugr-core/src/hugr/views/descendants.rs +++ b/hugr-core/src/hugr/views/descendants.rs @@ -207,7 +207,7 @@ pub(super) mod test { use crate::{ builder::{Container, Dataflow, DataflowSubContainer, HugrBuilder, ModuleBuilder}, type_row, - types::{FunctionType, Type}, + types::{Signature, Type}, utils::test_quantum_extension::{h_gate, EXTENSION_ID}, }; @@ -226,7 +226,7 @@ pub(super) mod test { let (f_id, inner_id) = { let mut func_builder = module_builder.define_function( "main", - FunctionType::new_endo(type_row![NAT, QB]).with_extension_delta(EXTENSION_ID), + Signature::new_endo(type_row![NAT, QB]).with_extension_delta(EXTENSION_ID), )?; let [int, qb] = func_builder.input_wires_arr(); @@ -235,7 +235,7 @@ pub(super) mod test { let inner_id = { let inner_builder = func_builder - .dfg_builder(FunctionType::new(type_row![NAT], type_row![NAT]), [int])?; + .dfg_builder(Signature::new(type_row![NAT], type_row![NAT]), [int])?; let w = inner_builder.input_wires(); inner_builder.finish_with_outputs(w) }?; @@ -263,7 +263,7 @@ pub(super) mod test { assert_eq!( region.poly_func_type(), Some( - FunctionType::new_endo(type_row![NAT, QB]) + Signature::new_endo(type_row![NAT, QB]) .with_extension_delta(EXTENSION_ID) .into() ) @@ -271,7 +271,7 @@ pub(super) mod test { let inner_region: DescendantsGraph = DescendantsGraph::try_new(&hugr, inner)?; assert_eq!( inner_region.inner_function_type(), - Some(FunctionType::new(type_row![NAT], type_row![NAT])) + Some(Signature::new(type_row![NAT], type_row![NAT])) ); Ok(()) diff --git a/hugr-core/src/hugr/views/root_checked.rs b/hugr-core/src/hugr/views/root_checked.rs index 668fdb83d..94ac05242 100644 --- a/hugr-core/src/hugr/views/root_checked.rs +++ b/hugr-core/src/hugr/views/root_checked.rs @@ -75,12 +75,12 @@ mod test { use crate::hugr::{HugrError, HugrMut}; use crate::ops::handle::{BasicBlockID, CfgID, DataflowParentID, DfgID}; use crate::ops::{DataflowBlock, MakeTuple, OpTag, OpType}; - use crate::{ops, type_row, types::FunctionType, Hugr, HugrView}; + use crate::{ops, type_row, types::Signature, Hugr, HugrView}; #[test] fn root_checked() { let root_type: OpType = ops::DFG { - signature: FunctionType::new(vec![], vec![]), + signature: Signature::new(vec![], vec![]), } .into(); let mut h = Hugr::new(root_type.clone()); diff --git a/hugr-core/src/hugr/views/sibling.rs b/hugr-core/src/hugr/views/sibling.rs index 5623b9330..1125bad25 100644 --- a/hugr-core/src/hugr/views/sibling.rs +++ b/hugr-core/src/hugr/views/sibling.rs @@ -385,7 +385,7 @@ mod test { use crate::ops::{dataflow::IOTrait, Input, OpTag, Output}; use crate::ops::{OpTrait, OpType}; use crate::type_row; - use crate::types::{FunctionType, Type}; + use crate::types::{Signature, Type}; use super::super::descendants::test::make_module_hgr; use super::*; @@ -409,7 +409,7 @@ mod test { #[test] fn nested_flat() -> Result<(), Box> { let mut module_builder = ModuleBuilder::new(); - let fty = FunctionType::new(type_row![NAT], type_row![NAT]); + let fty = Signature::new(type_row![NAT], type_row![NAT]); let mut fbuild = module_builder.define_function("main", fty.clone())?; let dfg = fbuild.dfg_builder(fty, fbuild.input_wires())?; let ins = dfg.input_wires(); diff --git a/hugr-core/src/hugr/views/sibling_subgraph.rs b/hugr-core/src/hugr/views/sibling_subgraph.rs index 07367e529..53c92ed56 100644 --- a/hugr-core/src/hugr/views/sibling_subgraph.rs +++ b/hugr-core/src/hugr/views/sibling_subgraph.rs @@ -23,7 +23,7 @@ use crate::hugr::{HugrMut, HugrView, RootTagged}; use crate::ops::dataflow::DataflowOpTrait; use crate::ops::handle::{ContainerHandle, DataflowOpID}; use crate::ops::{NamedOp, OpTag, OpTrait, OpType}; -use crate::types::{FunctionType, Type}; +use crate::types::{Signature, Type}; use crate::{Hugr, IncomingPort, Node, OutgoingPort, Port, SimpleReplacement}; /// A non-empty convex subgraph of a HUGR sibling graph. @@ -285,7 +285,7 @@ impl SiblingSubgraph { } /// The signature of the subgraph. - pub fn signature(&self, hugr: &impl HugrView) -> FunctionType { + pub fn signature(&self, hugr: &impl HugrView) -> Signature { let input = self .inputs .iter() @@ -303,7 +303,7 @@ impl SiblingSubgraph { sig.port_type(p).cloned().expect("must be dataflow edge") }) .collect_vec(); - FunctionType::new(input, output).with_extension_delta(ExtensionSet::union_over( + Signature::new(input, output).with_extension_delta(ExtensionSet::union_over( self.nodes.iter().map(|n| { hugr.signature(*n) .expect("all nodes must have dataflow signature") @@ -666,9 +666,9 @@ pub enum InvalidReplacement { ] InvalidSignature { /// The expected signature. - expected: FunctionType, + expected: Signature, /// The actual signature. - actual: Option, + actual: Option, }, /// SiblingSubgraph is not convex. #[error("SiblingSubgraph is not convex.")] @@ -733,7 +733,7 @@ mod tests { use cool_asserts::assert_matches; - use crate::builder::inout_ft; + use crate::builder::inout_sig; use crate::extension::PRELUDE_REGISTRY; use crate::std_extensions::logic; use crate::utils::test_quantum_extension::{self, cx_gate}; @@ -782,7 +782,7 @@ mod tests { let mut mod_builder = ModuleBuilder::new(); let func = mod_builder.declare( "test", - FunctionType::new_endo(type_row![QB_T, QB_T, QB_T]) + Signature::new_endo(type_row![QB_T, QB_T, QB_T]) .with_extension_delta(test_quantum_extension::EXTENSION_ID) .into(), )?; @@ -803,7 +803,7 @@ mod tests { let mut mod_builder = ModuleBuilder::new(); let func = mod_builder.declare( "test", - FunctionType::new_endo(type_row![BOOL_T]) + Signature::new_endo(type_row![BOOL_T]) .with_extension_delta(logic::EXTENSION_ID) .into(), )?; @@ -825,7 +825,7 @@ mod tests { let mut mod_builder = ModuleBuilder::new(); let func = mod_builder.declare( "test", - FunctionType::new(BOOL_T, type_row![BOOL_T, BOOL_T]) + Signature::new(BOOL_T, type_row![BOOL_T, BOOL_T]) .with_extension_delta(logic::EXTENSION_ID) .into(), )?; @@ -847,7 +847,7 @@ mod tests { let mut mod_builder = ModuleBuilder::new(); let func = mod_builder.declare( "test", - FunctionType::new_endo(BOOL_T) + Signature::new_endo(BOOL_T) .with_extension_delta(logic::EXTENSION_ID) .into(), )?; @@ -888,7 +888,7 @@ mod tests { let sub = SiblingSubgraph::try_new_dataflow_subgraph(&func)?; let empty_dfg = { - let builder = DFGBuilder::new(FunctionType::new_endo(type_row![QB_T, QB_T])).unwrap(); + let builder = DFGBuilder::new(Signature::new_endo(type_row![QB_T, QB_T])).unwrap(); let inputs = builder.input_wires(); builder.finish_prelude_hugr_with_outputs(inputs).unwrap() }; @@ -913,7 +913,7 @@ mod tests { // the first two qubits. assert_eq!( sub.signature(&func), - FunctionType::new_endo(type_row![QB_T, QB_T]) + Signature::new_endo(type_row![QB_T, QB_T]) .with_extension_delta(test_quantum_extension::EXTENSION_ID) ); Ok(()) @@ -926,7 +926,7 @@ mod tests { let sub = SiblingSubgraph::from_sibling_graph(&func)?; let empty_dfg = { - let builder = DFGBuilder::new(FunctionType::new_endo(type_row![QB_T])).unwrap(); + let builder = DFGBuilder::new(Signature::new_endo(type_row![QB_T])).unwrap(); let inputs = builder.input_wires(); builder.finish_prelude_hugr_with_outputs(inputs).unwrap() }; @@ -1081,7 +1081,7 @@ mod tests { let one_bit = type_row![BOOL_T]; let two_bit = type_row![BOOL_T, BOOL_T]; - let mut builder = DFGBuilder::new(inout_ft(one_bit.clone(), two_bit.clone())).unwrap(); + let mut builder = DFGBuilder::new(inout_sig(one_bit.clone(), two_bit.clone())).unwrap(); let inw = builder.input_wires().exactly_one().unwrap(); let outw1 = builder.add_dataflow_op(NotOp, [inw]).unwrap().out_wire(0); let outw2 = builder diff --git a/hugr-core/src/hugr/views/tests.rs b/hugr-core/src/hugr/views/tests.rs index 063e751d4..8f1811656 100644 --- a/hugr-core/src/hugr/views/tests.rs +++ b/hugr-core/src/hugr/views/tests.rs @@ -3,7 +3,7 @@ use rstest::{fixture, rstest}; use crate::{ builder::{ - endo_ft, inout_ft, BuildError, BuildHandle, Container, DFGBuilder, Dataflow, DataflowHugr, + endo_sig, inout_sig, BuildError, BuildHandle, Container, DFGBuilder, Dataflow, DataflowHugr, }, extension::prelude::QB_T, ops::{ @@ -11,14 +11,14 @@ use crate::{ Value, }, type_row, - types::FunctionType, + types::Signature, utils::test_quantum_extension::cx_gate, Hugr, HugrView, }; #[fixture] fn sample_hugr() -> (Hugr, BuildHandle, BuildHandle) { - let mut dfg = DFGBuilder::new(endo_ft(type_row![QB_T, QB_T])).unwrap(); + let mut dfg = DFGBuilder::new(endo_sig(type_row![QB_T, QB_T])).unwrap(); let [q1, q2] = dfg.input_wires_arr(); @@ -124,7 +124,7 @@ fn value_types() { use itertools::Itertools; let mut dfg = - DFGBuilder::new(inout_ft(type_row![QB_T, BOOL_T], type_row![BOOL_T, QB_T])).unwrap(); + DFGBuilder::new(inout_sig(type_row![QB_T, BOOL_T], type_row![BOOL_T, QB_T])).unwrap(); let [q, b] = dfg.input_wires_arr(); let n1 = dfg.add_dataflow_op(h_gate(), [q]).unwrap(); @@ -147,7 +147,7 @@ fn value_types() { fn static_targets() { use crate::extension::prelude::{ConstUsize, USIZE_T}; use itertools::Itertools; - let mut dfg = DFGBuilder::new(inout_ft(type_row![], type_row![USIZE_T])).unwrap(); + let mut dfg = DFGBuilder::new(inout_sig(type_row![], type_row![USIZE_T])).unwrap(); let c = dfg.add_constant(Value::extension(ConstUsize::new(1))); @@ -171,12 +171,12 @@ fn test_dataflow_ports_only() { use crate::std_extensions::logic::NotOp; use itertools::Itertools; - let mut dfg = DFGBuilder::new(endo_ft(BOOL_T)).unwrap(); + let mut dfg = DFGBuilder::new(endo_sig(BOOL_T)).unwrap(); let local_and = { let local_and = dfg .define_function( "and", - FunctionType::new(type_row![BOOL_T; 2], type_row![BOOL_T]), + Signature::new(type_row![BOOL_T; 2], type_row![BOOL_T]), ) .unwrap(); let first_input = local_and.input().out_wire(0); diff --git a/hugr-core/src/macros.rs b/hugr-core/src/macros.rs index dea66c5bc..51483aadc 100644 --- a/hugr-core/src/macros.rs +++ b/hugr-core/src/macros.rs @@ -43,11 +43,11 @@ pub(crate) use impl_box_clone; /// Example: /// ``` /// # use hugr::type_row; -/// # use hugr::types::{FunctionType, Type, TypeRow}; +/// # use hugr::types::{Signature, Type, TypeRow}; /// const U: Type = Type::UNIT; /// let static_row: TypeRow = type_row![U, U]; /// let dynamic_row: TypeRow = vec![U, U, U].into(); -/// let sig = FunctionType::new(static_row, dynamic_row); +/// let sig = Signature::new(static_row, dynamic_row); /// /// let repeated_row: TypeRow = type_row![U; 3]; /// assert_eq!(repeated_row, *sig.output()); diff --git a/hugr-core/src/ops.rs b/hugr-core/src/ops.rs index f44bfd136..1a2b000f6 100644 --- a/hugr-core/src/ops.rs +++ b/hugr-core/src/ops.rs @@ -10,7 +10,7 @@ pub mod module; pub mod tag; pub mod validate; use crate::extension::ExtensionSet; -use crate::types::{EdgeKind, FunctionType}; +use crate::types::{EdgeKind, Signature}; use crate::{Direction, OutgoingPort, Port}; use crate::{IncomingPort, PortIndex}; use paste::paste; @@ -343,7 +343,7 @@ pub trait OpTrait { /// The signature of the operation. /// /// Only dataflow operations have a signature, otherwise returns None. - fn dataflow_signature(&self) -> Option { + fn dataflow_signature(&self) -> Option { None } @@ -406,13 +406,13 @@ pub trait OpParent { /// sibling graph. /// /// Non-container ops like `FuncDecl` return `None` even though they represent a function. - fn inner_function_type(&self) -> Option { + fn inner_function_type(&self) -> Option { None } } impl OpParent for T { - fn inner_function_type(&self) -> Option { + fn inner_function_type(&self) -> Option { Some(DataflowParent::inner_signature(self)) } } diff --git a/hugr-core/src/ops/constant.rs b/hugr-core/src/ops/constant.rs index 6a8a7f8ee..b14e64d3a 100644 --- a/hugr-core/src/ops/constant.rs +++ b/hugr-core/src/ops/constant.rs @@ -5,7 +5,7 @@ mod custom; use super::{NamedOp, OpName, OpTrait, StaticTag}; use super::{OpTag, OpType}; use crate::extension::ExtensionSet; -use crate::types::{CustomType, EdgeKind, FunctionType, SumType, SumTypeError, Type}; +use crate::types::{CustomType, EdgeKind, Signature, SumType, SumTypeError, Type}; use crate::{Hugr, HugrView}; use delegate::delegate; @@ -131,6 +131,7 @@ pub struct Sum { impl Sum { /// If value is a sum with a single row variant, return the row. pub fn as_tuple(&self) -> Option<&[Value]> { + // For valid instances, the type row will not have any row variables. self.sum_type.as_tuple().map(|_| self.values.as_ref()) } } @@ -326,7 +327,7 @@ pub enum ConstTypeError { } /// Hugrs (even functions) inside Consts must be monomorphic -fn mono_fn_type(h: &Hugr) -> Result { +fn mono_fn_type(h: &Hugr) -> Result { let err = || ConstTypeError::NotMonomorphicFunction { hugr_root_type: h.root_type().clone(), }; @@ -527,7 +528,7 @@ pub type ValueNameRef = str; #[cfg(test)] mod test { use super::Value; - use crate::builder::inout_ft; + use crate::builder::inout_sig; use crate::builder::test::simple_dfg_hugr; use crate::std_extensions::arithmetic::int_types::ConstInt; use crate::{ @@ -588,7 +589,7 @@ mod test { let pred_rows = vec![type_row![USIZE_T, FLOAT64_TYPE], Type::EMPTY_TYPEROW]; let pred_ty = SumType::new(pred_rows.clone()); - let mut b = DFGBuilder::new(inout_ft( + let mut b = DFGBuilder::new(inout_sig( type_row![], TypeRow::from(vec![pred_ty.clone().into()]), ))?; @@ -603,7 +604,7 @@ mod test { let w = b.load_const(&c); b.finish_hugr_with_outputs([w], &test_registry()).unwrap(); - let mut b = DFGBuilder::new(FunctionType::new( + let mut b = DFGBuilder::new(Signature::new( type_row![], TypeRow::from(vec![pred_ty.clone().into()]), ))?; @@ -660,7 +661,7 @@ mod test { fn function_value(simple_dfg_hugr: Hugr) { let v = Value::function(simple_dfg_hugr).unwrap(); - let correct_type = Type::new_function(FunctionType::new_endo(type_row![ + let correct_type = Type::new_function(Signature::new_endo(type_row![ crate::extension::prelude::BOOL_T ])); @@ -752,14 +753,12 @@ mod test { 32, // Target around 32 total elements 3, // Each collection is up to 3 elements long |child_strat| { - (Type::any_non_row_var(), vec(child_strat, 0..3)).prop_map( - |(typ, children)| { - Self::new(ListValue::new( - typ, - children.into_iter().map(|e| Value::Extension { e }), - )) - }, - ) + (any::(), vec(child_strat, 0..3)).prop_map(|(typ, children)| { + Self::new(ListValue::new( + typ, + children.into_iter().map(|e| Value::Extension { e }), + )) + }) }, ) .boxed() diff --git a/hugr-core/src/ops/controlflow.rs b/hugr-core/src/ops/controlflow.rs index b1a6b0e37..ad60e7b86 100644 --- a/hugr-core/src/ops/controlflow.rs +++ b/hugr-core/src/ops/controlflow.rs @@ -1,7 +1,7 @@ //! Control flow operations. use crate::extension::ExtensionSet; -use crate::types::{EdgeKind, FunctionType, Type, TypeRow}; +use crate::types::{EdgeKind, Signature, Type, TypeRow}; use crate::Direction; use super::dataflow::{DataflowOpTrait, DataflowParent}; @@ -31,10 +31,10 @@ impl DataflowOpTrait for TailLoop { "A tail-controlled loop" } - fn signature(&self) -> FunctionType { + fn signature(&self) -> Signature { let [inputs, outputs] = [&self.just_inputs, &self.just_outputs].map(|row| row.extend(self.rest.iter())); - FunctionType::new(inputs, outputs).with_extension_delta(self.extension_delta.clone()) + Signature::new(inputs, outputs).with_extension_delta(self.extension_delta.clone()) } } @@ -54,8 +54,8 @@ impl TailLoop { } impl DataflowParent for TailLoop { - fn inner_signature(&self) -> FunctionType { - FunctionType::new(self.body_input_row(), self.body_output_row()) + fn inner_signature(&self) -> Signature { + Signature::new(self.body_input_row(), self.body_output_row()) .with_extension_delta(self.extension_delta.clone()) } } @@ -82,12 +82,12 @@ impl DataflowOpTrait for Conditional { "HUGR conditional operation" } - fn signature(&self) -> FunctionType { + fn signature(&self) -> Signature { let mut inputs = self.other_inputs.clone(); inputs .to_mut() .insert(0, Type::new_sum(self.sum_rows.clone())); - FunctionType::new(inputs, self.outputs.clone()) + Signature::new(inputs, self.outputs.clone()) .with_extension_delta(self.extension_delta.clone()) } } @@ -104,7 +104,7 @@ impl Conditional { #[allow(missing_docs)] #[cfg_attr(test, derive(proptest_derive::Arbitrary))] pub struct CFG { - pub signature: FunctionType, + pub signature: Signature, } impl_op_name!(CFG); @@ -116,7 +116,7 @@ impl DataflowOpTrait for CFG { "A dataflow node defined by a child CFG" } - fn signature(&self) -> FunctionType { + fn signature(&self) -> Signature { self.signature.clone() } } @@ -162,12 +162,12 @@ impl StaticTag for ExitBlock { } impl DataflowParent for DataflowBlock { - fn inner_signature(&self) -> FunctionType { + fn inner_signature(&self) -> Signature { // The node outputs a Sum before the data outputs of the block node let sum_type = Type::new_sum(self.sum_rows.clone()); let mut node_outputs = vec![sum_type]; node_outputs.extend_from_slice(&self.other_outputs); - FunctionType::new(self.inputs.clone(), TypeRow::from(node_outputs)) + Signature::new(self.inputs.clone(), TypeRow::from(node_outputs)) .with_extension_delta(self.extension_delta.clone()) } } @@ -260,7 +260,7 @@ impl BasicBlock for ExitBlock { /// Case ops - nodes valid inside Conditional nodes. pub struct Case { /// The signature of the contained dataflow graph. - pub signature: FunctionType, + pub signature: Signature, } impl_op_name!(Case); @@ -270,7 +270,7 @@ impl StaticTag for Case { } impl DataflowParent for Case { - fn inner_signature(&self) -> FunctionType { + fn inner_signature(&self) -> Signature { self.signature.clone() } } diff --git a/hugr-core/src/ops/custom.rs b/hugr-core/src/ops/custom.rs index b85afdac6..d295a18ba 100644 --- a/hugr-core/src/ops/custom.rs +++ b/hugr-core/src/ops/custom.rs @@ -14,7 +14,7 @@ use crate::extension::{ConstFoldResult, ExtensionId, ExtensionRegistry, OpDef, S use crate::hugr::internal::HugrMutInternals; use crate::hugr::HugrView; use crate::types::EdgeKind; -use crate::types::{type_param::TypeArg, FunctionType}; +use crate::types::{type_param::TypeArg, Signature}; use crate::{ops, Hugr, IncomingPort, Node}; use super::dataflow::DataflowOpTrait; @@ -132,7 +132,7 @@ impl DataflowOpTrait for CustomOp { } /// The signature of the operation. - fn signature(&self) -> FunctionType { + fn signature(&self) -> Signature { match self { Self::Opaque(op) => op.signature.clone(), Self::Extension(ext_op) => ext_op.signature(), @@ -181,7 +181,7 @@ pub struct ExtensionOp { )] def: Arc, args: Vec, - signature: FunctionType, // Cache + signature: Signature, // Cache } impl ExtensionOp { @@ -271,7 +271,7 @@ impl DataflowOpTrait for ExtensionOp { self.def().description() } - fn signature(&self) -> FunctionType { + fn signature(&self) -> Signature { self.signature.clone() } } @@ -286,7 +286,7 @@ pub struct OpaqueOp { #[cfg_attr(test, proptest(strategy = "any_nonempty_string()"))] description: String, // cache in advance so description() can return &str args: Vec, - signature: FunctionType, + signature: Signature, } fn qualify_name(res_id: &ExtensionId, op_name: &OpNameRef) -> OpName { @@ -300,7 +300,7 @@ impl OpaqueOp { op_name: impl Into, description: String, args: impl Into>, - signature: FunctionType, + signature: Signature, ) -> Self { Self { extension, @@ -342,7 +342,7 @@ impl DataflowOpTrait for OpaqueOp { &self.description } - fn signature(&self) -> FunctionType { + fn signature(&self) -> Signature { self.signature.clone() } } @@ -422,8 +422,8 @@ pub enum CustomOpError { SignatureMismatch { extension: ExtensionId, op: OpName, - stored: FunctionType, - computed: FunctionType, + stored: Signature, + computed: Signature, }, } @@ -441,7 +441,7 @@ mod test { #[test] fn new_opaque_op() { - let sig = FunctionType::new_endo(vec![QB_T]); + let sig = Signature::new_endo(vec![QB_T]); let op: CustomOp = OpaqueOp::new( "res".try_into().unwrap(), "op", @@ -468,7 +468,7 @@ mod test { "itobool", "description".into(), vec![], - FunctionType::new(i0.clone(), BOOL_T), + Signature::new(i0.clone(), BOOL_T), ); let resolved = super::resolve_opaque_op(Node::from(portgraph::NodeIndex::new(1)), &opaque, registry) diff --git a/hugr-core/src/ops/dataflow.rs b/hugr-core/src/ops/dataflow.rs index 0e6dc1800..364429784 100644 --- a/hugr-core/src/ops/dataflow.rs +++ b/hugr-core/src/ops/dataflow.rs @@ -4,7 +4,7 @@ use super::{impl_op_name, OpTag, OpTrait}; use crate::extension::{ExtensionRegistry, ExtensionSet, SignatureError}; use crate::ops::StaticTag; -use crate::types::{EdgeKind, FunctionType, PolyFuncType, Type, TypeArg, TypeRow}; +use crate::types::{EdgeKind, PolyFuncType, Signature, Type, TypeArg, TypeRow}; use crate::IncomingPort; #[cfg(test)] @@ -19,7 +19,7 @@ pub trait DataflowOpTrait { fn description(&self) -> &str; /// The signature of the operation. - fn signature(&self) -> FunctionType; + fn signature(&self) -> Signature; /// The edge kind for the non-dataflow or constant inputs of the operation, /// not described by the signature. @@ -105,8 +105,8 @@ impl DataflowOpTrait for Input { None } - fn signature(&self) -> FunctionType { - FunctionType::new(TypeRow::new(), self.types.clone()) + fn signature(&self) -> Signature { + Signature::new(TypeRow::new(), self.types.clone()) } } impl DataflowOpTrait for Output { @@ -118,8 +118,8 @@ impl DataflowOpTrait for Output { // Note: We know what the input extensions should be, so we *could* give an // instantiated Signature instead - fn signature(&self) -> FunctionType { - FunctionType::new(self.types.clone(), TypeRow::new()) + fn signature(&self) -> Signature { + Signature::new(self.types.clone(), TypeRow::new()) } fn other_output(&self) -> Option { @@ -134,7 +134,7 @@ impl OpTrait for T { fn tag(&self) -> OpTag { T::TAG } - fn dataflow_signature(&self) -> Option { + fn dataflow_signature(&self) -> Option { Some(DataflowOpTrait::signature(self)) } fn extension_delta(&self) -> ExtensionSet { @@ -169,7 +169,7 @@ pub struct Call { /// The type arguments that instantiate `func_sig`. pub type_args: Vec, /// The instantiation of `func_sig`. - pub instantiation: FunctionType, // Cache, so we can fail in try_new() not in signature() + pub instantiation: Signature, // Cache, so we can fail in try_new() not in signature() } impl_op_name!(Call); @@ -180,7 +180,7 @@ impl DataflowOpTrait for Call { "Call a function directly" } - fn signature(&self) -> FunctionType { + fn signature(&self) -> Signature { self.instantiation.clone() } @@ -220,10 +220,10 @@ impl Call { /// ``` /// # use hugr::ops::dataflow::Call; /// # use hugr::ops::OpType; - /// # use hugr::types::FunctionType; + /// # use hugr::types::Signature; /// # use hugr::extension::prelude::QB_T; /// # use hugr::extension::PRELUDE_REGISTRY; - /// let signature = FunctionType::new(vec![QB_T, QB_T], vec![QB_T, QB_T]); + /// let signature = Signature::new(vec![QB_T, QB_T], vec![QB_T, QB_T]); /// let call = Call::try_new(signature.into(), &[], &PRELUDE_REGISTRY).unwrap(); /// let op = OpType::Call(call.clone()); /// assert_eq!(op.static_input_port(), Some(call.called_function_port())); @@ -261,7 +261,7 @@ impl Call { #[cfg_attr(test, derive(Arbitrary))] pub struct CallIndirect { /// Signature of function being called - pub signature: FunctionType, + pub signature: Signature, } impl_op_name!(CallIndirect); @@ -272,7 +272,7 @@ impl DataflowOpTrait for CallIndirect { "Call a function indirectly" } - fn signature(&self) -> FunctionType { + fn signature(&self) -> Signature { let mut s = self.signature.clone(); s.input .to_mut() @@ -296,8 +296,8 @@ impl DataflowOpTrait for LoadConstant { "Load a static constant in to the local dataflow graph" } - fn signature(&self) -> FunctionType { - FunctionType::new(TypeRow::new(), vec![self.datatype.clone()]) + fn signature(&self) -> Signature { + Signature::new(TypeRow::new(), vec![self.datatype.clone()]) } fn static_input(&self) -> Option { @@ -341,7 +341,7 @@ pub struct LoadFunction { /// The type arguments that instantiate `func_sig`. pub type_args: Vec, /// The instantiation of `func_sig`. - pub signature: FunctionType, // Cache, so we can fail in try_new() not in signature() + pub signature: Signature, // Cache, so we can fail in try_new() not in signature() } impl_op_name!(LoadFunction); impl DataflowOpTrait for LoadFunction { @@ -351,7 +351,7 @@ impl DataflowOpTrait for LoadFunction { "Load a static function in to the local dataflow graph" } - fn signature(&self) -> FunctionType { + fn signature(&self) -> Signature { self.signature.clone() } @@ -371,7 +371,7 @@ impl LoadFunction { ) -> Result { let type_args = type_args.into(); let instantiation = func_sig.instantiate(&type_args, exts)?; - let signature = FunctionType::new(TypeRow::new(), vec![Type::new_function(instantiation)]); + let signature = Signature::new(TypeRow::new(), vec![Type::new_function(instantiation)]); Ok(Self { func_sig, type_args, @@ -418,7 +418,7 @@ impl LoadFunction { /// Operations that is the parent of a dataflow graph. pub trait DataflowParent { /// Signature of the inner dataflow graph. - fn inner_signature(&self) -> FunctionType; + fn inner_signature(&self) -> Signature; } /// A simply nested dataflow graph. @@ -426,13 +426,13 @@ pub trait DataflowParent { #[cfg_attr(test, derive(Arbitrary))] pub struct DFG { /// Signature of DFG node - pub signature: FunctionType, + pub signature: Signature, } impl_op_name!(DFG); impl DataflowParent for DFG { - fn inner_signature(&self) -> FunctionType { + fn inner_signature(&self) -> Signature { self.signature.clone() } } @@ -444,7 +444,7 @@ impl DataflowOpTrait for DFG { "A simply nested dataflow graph" } - fn signature(&self) -> FunctionType { + fn signature(&self) -> Signature { self.inner_signature() } } diff --git a/hugr-core/src/ops/leaf.rs b/hugr-core/src/ops/leaf.rs index 4fc84e85e..ab6171901 100644 --- a/hugr-core/src/ops/leaf.rs +++ b/hugr-core/src/ops/leaf.rs @@ -7,7 +7,7 @@ use crate::extension::ExtensionSet; use crate::{ extension::ExtensionId, - types::{EdgeKind, FunctionType, Type, TypeRow}, + types::{EdgeKind, Signature, Type, TypeRow}, }; /// A no-op operation. @@ -72,6 +72,8 @@ pub struct Tag { /// The variant to create. pub tag: usize, /// The variants of the sum type. + /// TODO this allows *none* of the variants to contain row variables, but + /// we could allow variants *other than the tagged one* to contain rowvars. pub variants: Vec, } @@ -119,8 +121,8 @@ impl DataflowOpTrait for Noop { } /// The signature of the operation. - fn signature(&self) -> FunctionType { - FunctionType::new(vec![self.ty.clone()], vec![self.ty.clone()]) + fn signature(&self) -> Signature { + Signature::new(vec![self.ty.clone()], vec![self.ty.clone()]) } fn other_input(&self) -> Option { @@ -141,8 +143,8 @@ impl DataflowOpTrait for MakeTuple { } /// The signature of the operation. - fn signature(&self) -> FunctionType { - FunctionType::new(self.tys.clone(), vec![Type::new_tuple(self.tys.clone())]) + fn signature(&self) -> Signature { + Signature::new(self.tys.clone(), vec![Type::new_tuple(self.tys.clone())]) } fn other_input(&self) -> Option { @@ -163,8 +165,8 @@ impl DataflowOpTrait for UnpackTuple { } /// The signature of the operation. - fn signature(&self) -> FunctionType { - FunctionType::new(vec![Type::new_tuple(self.tys.clone())], self.tys.clone()) + fn signature(&self) -> Signature { + Signature::new(vec![Type::new_tuple(self.tys.clone())], self.tys.clone()) } fn other_input(&self) -> Option { @@ -185,8 +187,8 @@ impl DataflowOpTrait for Tag { } /// The signature of the operation. - fn signature(&self) -> FunctionType { - FunctionType::new( + fn signature(&self) -> Signature { + Signature::new( self.variants .get(self.tag) .expect("Not a valid tag") @@ -213,8 +215,8 @@ impl DataflowOpTrait for Lift { } /// The signature of the operation. - fn signature(&self) -> FunctionType { - FunctionType::new(self.type_row.clone(), self.type_row.clone()) + fn signature(&self) -> Signature { + Signature::new(self.type_row.clone(), self.type_row.clone()) .with_extension_delta(ExtensionSet::singleton(&self.new_extension)) } diff --git a/hugr-core/src/ops/module.rs b/hugr-core/src/ops/module.rs index ea4e67744..cb10d4c2f 100644 --- a/hugr-core/src/ops/module.rs +++ b/hugr-core/src/ops/module.rs @@ -7,7 +7,7 @@ use { ::proptest_derive::Arbitrary, }; -use crate::types::{EdgeKind, FunctionType, PolyFuncType}; +use crate::types::{EdgeKind, PolyFuncType, Signature}; use crate::types::{Type, TypeBound}; use super::dataflow::DataflowParent; @@ -64,7 +64,7 @@ impl StaticTag for FuncDefn { } impl DataflowParent for FuncDefn { - fn inner_signature(&self) -> FunctionType { + fn inner_signature(&self) -> Signature { self.signature.body().clone() } } diff --git a/hugr-core/src/std_extensions/arithmetic/conversions.rs b/hugr-core/src/std_extensions/arithmetic/conversions.rs index 5125d3a60..8f7110807 100644 --- a/hugr-core/src/std_extensions/arithmetic/conversions.rs +++ b/hugr-core/src/std_extensions/arithmetic/conversions.rs @@ -12,7 +12,7 @@ use crate::{ }, ops::{custom::ExtensionOp, NamedOp}, type_row, - types::{FunctionType, PolyFuncType, TypeArg}, + types::{FuncValueType, PolyFuncTypeRV, TypeArg, TypeRV}, Extension, }; @@ -45,20 +45,18 @@ impl MakeOpDef for ConvertOpDef { fn signature(&self) -> SignatureFunc { use ConvertOpDef::*; - match self { - trunc_s | trunc_u => PolyFuncType::new( - vec![LOG_WIDTH_TYPE_PARAM], - FunctionType::new( + PolyFuncTypeRV::new( + vec![LOG_WIDTH_TYPE_PARAM], + match self { + trunc_s | trunc_u => FuncValueType::new( type_row![FLOAT64_TYPE], - vec![sum_with_error(int_tv(0)).into()], + TypeRV::from(sum_with_error(int_tv(0))), ), - ), - - convert_s | convert_u => PolyFuncType::new( - vec![LOG_WIDTH_TYPE_PARAM], - FunctionType::new(vec![int_tv(0)], type_row![FLOAT64_TYPE]), - ), - } + convert_s | convert_u => { + FuncValueType::new(vec![int_tv(0)], type_row![FLOAT64_TYPE]) + } + }, + ) .into() } diff --git a/hugr-core/src/std_extensions/arithmetic/float_ops.rs b/hugr-core/src/std_extensions/arithmetic/float_ops.rs index b098d89dd..f701da233 100644 --- a/hugr-core/src/std_extensions/arithmetic/float_ops.rs +++ b/hugr-core/src/std_extensions/arithmetic/float_ops.rs @@ -10,7 +10,7 @@ use crate::{ ExtensionId, ExtensionRegistry, ExtensionSet, OpDef, SignatureFunc, PRELUDE, }, type_row, - types::FunctionType, + types::Signature, Extension, }; use lazy_static::lazy_static; @@ -56,13 +56,13 @@ impl MakeOpDef for FloatOps { match self { feq | fne | flt | fgt | fle | fge => { - FunctionType::new(type_row![FLOAT64_TYPE; 2], type_row![BOOL_T]) + Signature::new(type_row![FLOAT64_TYPE; 2], type_row![BOOL_T]) } fmax | fmin | fadd | fsub | fmul | fdiv => { - FunctionType::new(type_row![FLOAT64_TYPE; 2], type_row![FLOAT64_TYPE]) + Signature::new(type_row![FLOAT64_TYPE; 2], type_row![FLOAT64_TYPE]) } - fneg | fabs | ffloor | fceil => FunctionType::new_endo(type_row![FLOAT64_TYPE]), - ftostring => FunctionType::new(type_row![FLOAT64_TYPE], STRING_TYPE), + fneg | fabs | ffloor | fceil => Signature::new_endo(type_row![FLOAT64_TYPE]), + ftostring => Signature::new(type_row![FLOAT64_TYPE], STRING_TYPE), } .into() } diff --git a/hugr-core/src/std_extensions/arithmetic/int_ops.rs b/hugr-core/src/std_extensions/arithmetic/int_ops.rs index 130e8a43d..d7f539682 100644 --- a/hugr-core/src/std_extensions/arithmetic/int_ops.rs +++ b/hugr-core/src/std_extensions/arithmetic/int_ops.rs @@ -10,12 +10,12 @@ use crate::ops::custom::ExtensionOp; use crate::ops::{NamedOp, OpName}; use crate::std_extensions::arithmetic::int_types::int_type; use crate::type_row; -use crate::types::{FunctionType, PolyFuncType}; +use crate::types::{FuncValueType, PolyFuncTypeRV, TypeRowRV}; use crate::utils::collect_array; use crate::{ extension::{ExtensionId, ExtensionSet, SignatureError}, - types::{type_param::TypeArg, Type, TypeRow}, + types::{type_param::TypeArg, Type}, Extension, }; @@ -116,7 +116,7 @@ impl MakeOpDef for IntOpDef { ) .into(), inarrow_s | inarrow_u => CustomValidator::new_with_validator( - int_polytype(2, vec![int_tv(0)], vec![sum_with_error(int_tv(1)).into()]), + int_polytype(2, int_tv(0), sum_ty_with_err(int_tv(1))), IOValidator { f_ge_s: true }, ) .into(), @@ -131,30 +131,27 @@ impl MakeOpDef for IntOpDef { ineg | iabs | inot => iunop_sig().into(), //TODO inline idivmod_checked_u | idivmod_checked_s => { - let intpair: TypeRow = vec![int_tv(0), int_tv(1)].into(); + let intpair: TypeRowRV = vec![int_tv(0), int_tv(1)].into(); int_polytype( 2, intpair.clone(), - vec![sum_with_error(Type::new_tuple(intpair)).into()], + sum_ty_with_err(Type::new_tuple(intpair)), ) } .into(), idivmod_u | idivmod_s => { - let intpair: TypeRow = vec![int_tv(0), int_tv(1)].into(); + let intpair: TypeRowRV = vec![int_tv(0), int_tv(1)].into(); int_polytype(2, intpair.clone(), intpair.clone()) } .into(), idiv_u | idiv_s => int_polytype(2, vec![int_tv(0), int_tv(1)], vec![int_tv(0)]).into(), - idiv_checked_u | idiv_checked_s => int_polytype( - 2, - vec![int_tv(0), int_tv(1)], - vec![sum_with_error(int_tv(0)).into()], - ) - .into(), + idiv_checked_u | idiv_checked_s => { + int_polytype(2, vec![int_tv(0), int_tv(1)], sum_ty_with_err(int_tv(0))).into() + } imod_checked_u | imod_checked_s => int_polytype( 2, vec![int_tv(0), int_tv(1).clone()], - vec![sum_with_error(int_tv(1)).into()], + sum_ty_with_err(int_tv(1)), ) .into(), imod_u | imod_s => { @@ -163,9 +160,9 @@ impl MakeOpDef for IntOpDef { ishl | ishr | irotl | irotr => { int_polytype(2, vec![int_tv(0), int_tv(1)], vec![int_tv(0)]).into() } - itostring_u | itostring_s => PolyFuncType::new( + itostring_u | itostring_s => PolyFuncTypeRV::new( vec![LOG_WIDTH_TYPE_PARAM], - FunctionType::new(vec![int_tv(0)], vec![STRING_TYPE]), + FuncValueType::new(vec![int_tv(0)], vec![STRING_TYPE]), ) .into(), } @@ -239,22 +236,22 @@ impl MakeOpDef for IntOpDef { } fn int_polytype( n_vars: usize, - input: impl Into, - output: impl Into, -) -> PolyFuncType { - PolyFuncType::new( + input: impl Into, + output: impl Into, +) -> PolyFuncTypeRV { + PolyFuncTypeRV::new( vec![LOG_WIDTH_TYPE_PARAM; n_vars], - FunctionType::new(input, output), + FuncValueType::new(input, output), ) } -fn ibinop_sig() -> PolyFuncType { +fn ibinop_sig() -> PolyFuncTypeRV { let int_type_var = int_tv(0); int_polytype(1, vec![int_type_var.clone(); 2], vec![int_type_var]) } -fn iunop_sig() -> PolyFuncType { +fn iunop_sig() -> PolyFuncTypeRV { let int_type_var = int_tv(0); int_polytype(1, vec![int_type_var.clone()], vec![int_type_var]) } @@ -351,9 +348,16 @@ impl IntOpDef { } } +fn sum_ty_with_err(t: Type) -> Type { + sum_with_error(t).into() +} + #[cfg(test)] mod test { - use crate::{ops::dataflow::DataflowOpTrait, std_extensions::arithmetic::int_types::int_type}; + use crate::{ + ops::dataflow::DataflowOpTrait, std_extensions::arithmetic::int_types::int_type, + types::Signature, + }; use super::*; @@ -375,7 +379,7 @@ mod test { .to_extension_op() .unwrap() .signature(), - FunctionType::new(int_type(3), int_type(4)).with_extension_delta(EXTENSION_ID) + Signature::new(int_type(3), int_type(4)).with_extension_delta(EXTENSION_ID) ); assert_eq!( IntOpDef::iwiden_s @@ -383,7 +387,7 @@ mod test { .to_extension_op() .unwrap() .signature(), - FunctionType::new_endo(int_type(3)).with_extension_delta(EXTENSION_ID) + Signature::new_endo(int_type(3)).with_extension_delta(EXTENSION_ID) ); assert_eq!( IntOpDef::inarrow_s @@ -391,7 +395,7 @@ mod test { .to_extension_op() .unwrap() .signature(), - FunctionType::new(vec![int_type(3)], vec![sum_with_error(int_type(3)).into()]) + Signature::new(int_type(3), sum_ty_with_err(int_type(3))) .with_extension_delta(EXTENSION_ID) ); assert!( @@ -408,7 +412,7 @@ mod test { .to_extension_op() .unwrap() .signature(), - FunctionType::new(vec![int_type(2)], vec![sum_with_error(int_type(1)).into()]) + Signature::new(int_type(2), sum_ty_with_err(int_type(1))) .with_extension_delta(EXTENSION_ID) ); diff --git a/hugr-core/src/std_extensions/collections.rs b/hugr-core/src/std_extensions/collections.rs index 392417dff..0fb809d16 100644 --- a/hugr-core/src/std_extensions/collections.rs +++ b/hugr-core/src/std_extensions/collections.rs @@ -17,7 +17,7 @@ use crate::{ ops::{self, custom::ExtensionOp, NamedOp}, types::{ type_param::{TypeArg, TypeParam}, - CustomCheckFailure, CustomType, FunctionType, PolyFuncType, Type, TypeBound, + CustomCheckFailure, CustomType, FuncValueType, PolyFuncTypeRV, Type, TypeBound, }, utils::sorted_consts, Extension, @@ -155,9 +155,9 @@ fn extension() -> Extension { .add_op( POP_NAME, "Pop from back of list".into(), - PolyFuncType::new( + PolyFuncTypeRV::new( vec![TP], - FunctionType::new(vec![l.clone()], vec![l.clone(), e.clone()]), + FuncValueType::new(vec![l.clone()], vec![l.clone(), e.clone()]), ), ) .unwrap() @@ -166,7 +166,7 @@ fn extension() -> Extension { .add_op( PUSH_NAME, "Push to back of list".into(), - PolyFuncType::new(vec![TP], FunctionType::new(vec![l.clone(), e], vec![l])), + PolyFuncTypeRV::new(vec![TP], FuncValueType::new(vec![l.clone(), e], vec![l])), ) .unwrap() .set_constant_folder(PushFold); diff --git a/hugr-core/src/std_extensions/logic.rs b/hugr-core/src/std_extensions/logic.rs index 52e3904ad..cb5454285 100644 --- a/hugr-core/src/std_extensions/logic.rs +++ b/hugr-core/src/std_extensions/logic.rs @@ -5,6 +5,7 @@ use strum_macros::{EnumIter, EnumString, IntoStaticStr}; use crate::extension::{ConstFold, ConstFoldResult}; use crate::ops::constant::ValueName; use crate::ops::{OpName, Value}; +use crate::types::{FuncValueType, Signature}; use crate::{ extension::{ prelude::BOOL_T, @@ -13,10 +14,7 @@ use crate::{ }, ops::{self, custom::ExtensionOp, NamedOp}, type_row, - types::{ - type_param::{TypeArg, TypeParam}, - FunctionType, - }, + types::type_param::{TypeArg, TypeParam}, utils::sorted_consts, Extension, IncomingPort, }; @@ -136,7 +134,7 @@ impl MakeOpDef for NotOp { } fn signature(&self) -> SignatureFunc { - FunctionType::new_endo(type_row![BOOL_T]).into() + Signature::new_endo(type_row![BOOL_T]).into() } fn description(&self) -> String { "logical 'not'".into() @@ -164,13 +162,13 @@ fn logic_op_sig() -> impl SignatureFromArgs { fn compute_signature( &self, arg_values: &[TypeArg], - ) -> Result { + ) -> Result { // get the number of input booleans. let [TypeArg::BoundedNat { n }] = *arg_values else { return Err(SignatureError::InvalidTypeArgs); }; let var_arg_row = vec![BOOL_T; n as usize]; - Ok(FunctionType::new(var_arg_row, vec![BOOL_T]).into()) + Ok(FuncValueType::new(var_arg_row, vec![BOOL_T]).into()) } fn static_params(&self) -> &[TypeParam] { diff --git a/hugr-core/src/types.rs b/hugr-core/src/types.rs index 3bb0eafbd..9747fd0e0 100644 --- a/hugr-core/src/types.rs +++ b/hugr-core/src/types.rs @@ -3,33 +3,36 @@ mod check; pub mod custom; mod poly_func; +mod row_var; mod serialize; mod signature; pub mod type_param; pub mod type_row; +use row_var::MaybeRV; +pub use row_var::{NoRV, RowVariable}; pub use crate::ops::constant::{ConstTypeError, CustomCheckFailure}; use crate::types::type_param::check_type_arg; use crate::utils::display_list_with_separator; pub use check::SumTypeError; pub use custom::CustomType; -pub use poly_func::PolyFuncType; -pub use signature::FunctionType; +pub use poly_func::{PolyFuncType, PolyFuncTypeRV}; +pub use signature::{FuncValueType, Signature}; use smol_str::SmolStr; pub use type_param::TypeArg; -pub use type_row::TypeRow; +pub use type_row::{TypeRow, TypeRowRV}; use itertools::FoldWhile::{Continue, Done}; use itertools::{repeat_n, Itertools}; -use serde::{Deserialize, Serialize}; #[cfg(test)] -use {crate::proptest::RecursionDepth, ::proptest::prelude::*, proptest_derive::Arbitrary}; +use proptest_derive::Arbitrary; +use serde::{Deserialize, Serialize}; use crate::extension::{ExtensionRegistry, SignatureError}; use crate::ops::AliasDecl; -use crate::type_row; use self::type_param::TypeParam; +use self::type_row::TypeRowBase; /// A unique identifier for a type. pub type TypeName = SmolStr; @@ -47,7 +50,7 @@ pub enum EdgeKind { Value(Type), /// A reference to a static constant value - must be a Copyable type Const(Type), - /// A reference to a function i.e. [FuncDecl] or [FuncDefn] + /// A reference to a function i.e. [FuncDecl] or [FuncDefn]. /// /// [FuncDecl]: crate::ops::FuncDecl /// [FuncDefn]: crate::ops::FuncDefn @@ -130,7 +133,7 @@ pub enum SumType { Unit { size: u8 }, /// General case of a Sum type. #[allow(missing_docs)] - General { rows: Vec }, + General { rows: Vec }, } impl std::fmt::Display for SumType { @@ -152,12 +155,12 @@ impl SumType { /// Initialize a new sum type. pub fn new(variants: impl IntoIterator) -> Self where - V: Into, + V: Into, { let rows = variants.into_iter().map(Into::into).collect_vec(); let len: usize = rows.len(); - if len <= (u8::MAX as usize) && rows.iter().all(TypeRow::is_empty) { + if len <= (u8::MAX as usize) && rows.iter().all(TypeRowRV::is_empty) { Self::new_unary(len as u8) } else { Self::General { rows } @@ -175,9 +178,9 @@ impl SumType { } /// Report the tag'th variant, if it exists. - pub fn get_variant(&self, tag: usize) -> Option<&TypeRow> { + pub fn get_variant(&self, tag: usize) -> Option<&TypeRowRV> { match self { - SumType::Unit { size } if tag < (*size as usize) => Some(Type::EMPTY_TYPEROW_REF), + SumType::Unit { size } if tag < (*size as usize) => Some(TypeRV::EMPTY_TYPEROW_REF), SumType::General { rows } => rows.get(tag), _ => None, } @@ -192,81 +195,74 @@ impl SumType { } /// Returns variant row if there is only one variant - pub fn as_tuple(&self) -> Option<&TypeRow> { + pub fn as_tuple(&self) -> Option<&TypeRowRV> { match self { - SumType::Unit { size } if *size == 1 => Some(Type::EMPTY_TYPEROW_REF), + SumType::Unit { size } if *size == 1 => Some(TypeRV::EMPTY_TYPEROW_REF), SumType::General { rows } if rows.len() == 1 => Some(&rows[0]), _ => None, } } } -impl From for Type { - fn from(sum: SumType) -> Type { +impl From for TypeBase { + fn from(sum: SumType) -> Self { match sum { - SumType::Unit { size } => Type::new_unit_sum(size), - SumType::General { rows } => Type::new_sum(rows), + SumType::Unit { size } => TypeBase::new_unit_sum(size), + SumType::General { rows } => TypeBase::new_sum(rows), } } } -#[derive(Clone, PartialEq, Debug, Eq, derive_more::Display)] -#[cfg_attr(test, derive(Arbitrary), proptest(params = "RecursionDepth"))] +#[derive(Clone, Debug, Eq, derive_more::Display)] /// Core types -pub enum TypeEnum { +pub enum TypeEnum { // TODO optimise with Box ? // or some static version of this? #[allow(missing_docs)] - Extension( - #[cfg_attr(test, proptest(strategy = "any_with::(params.into())"))] CustomType, - ), + Extension(CustomType), #[allow(missing_docs)] #[display(fmt = "Alias({})", "_0.name()")] Alias(AliasDecl), #[allow(missing_docs)] #[display(fmt = "Function({})", "_0")] - Function( - #[cfg_attr( - test, - proptest(strategy = "any_with::(params).prop_map(Box::new)") - )] - Box, - ), + Function(Box), // Index into TypeParams, and cache of TypeBound (checked in validation) #[allow(missing_docs)] #[display(fmt = "Variable({})", _0)] Variable(usize, TypeBound), - /// Variable index, and cache of inner TypeBound - matches a [TypeParam::List] of [TypeParam::Type] - /// of this bound (checked in validation) + /// RowVariable. Of course, this requires that `RV` has instances, [NoRV] doesn't. #[display(fmt = "RowVar({})", _0)] - RowVariable(usize, TypeBound), + RowVar(RV), #[allow(missing_docs)] #[display(fmt = "{}", "_0")] - Sum(#[cfg_attr(test, proptest(strategy = "any_with::(params)"))] SumType), + Sum(SumType), } -impl TypeEnum { + +impl TypeEnum { /// The smallest type bound that covers the whole type. fn least_upper_bound(&self) -> TypeBound { match self { TypeEnum::Extension(c) => c.bound(), TypeEnum::Alias(a) => a.bound, TypeEnum::Function(_) => TypeBound::Copyable, - TypeEnum::Variable(_, b) | TypeEnum::RowVariable(_, b) => *b, + TypeEnum::Variable(_, b) => *b, + TypeEnum::RowVar(b) => b.bound(), TypeEnum::Sum(SumType::Unit { size: _ }) => TypeBound::Eq, TypeEnum::Sum(SumType::General { rows }) => least_upper_bound( rows.iter() - .flat_map(TypeRow::iter) - .map(Type::least_upper_bound), + .flat_map(TypeRowRV::iter) + .map(TypeRV::least_upper_bound), ), } } } -#[derive( - Clone, PartialEq, Debug, Eq, derive_more::Display, serde::Serialize, serde::Deserialize, -)] +#[derive(Clone, Debug, Eq, derive_more::Display, serde::Serialize, serde::Deserialize)] #[display(fmt = "{}", "_0")] -#[serde(into = "serialize::SerSimpleType", from = "serialize::SerSimpleType")] +#[serde( + into = "serialize::SerSimpleType", + try_from = "serialize::SerSimpleType" +)] /// A HUGR type - the valid types of [EdgeKind::Value] and [EdgeKind::Const] edges. /// Such an edge is valid if the ports on either end agree on the [Type]. /// Types have an optional [TypeBound] which places limits on the valid @@ -282,29 +278,56 @@ impl TypeEnum { /// ``` /// /// ``` -/// # use hugr::types::{Type, TypeBound, FunctionType}; +/// # use hugr::types::{Type, TypeBound, Signature}; /// -/// let func_type = Type::new_function(FunctionType::new_endo(vec![])); +/// let func_type: Type = Type::new_function(Signature::new_endo(vec![])); /// assert_eq!(func_type.least_upper_bound(), TypeBound::Copyable); /// ``` -pub struct Type(TypeEnum, TypeBound); +pub struct TypeBase(TypeEnum, TypeBound); + +/// The type of a single value, that can be sent down a wire +pub type Type = TypeBase; + +/// One or more types - either a single type, or a row variable +/// standing for multiple types. +pub type TypeRV = TypeBase; + +impl PartialEq> for TypeEnum { + fn eq(&self, other: &TypeEnum) -> bool { + match (self, other) { + (TypeEnum::Extension(e1), TypeEnum::Extension(e2)) => e1 == e2, + (TypeEnum::Alias(a1), TypeEnum::Alias(a2)) => a1 == a2, + (TypeEnum::Function(f1), TypeEnum::Function(f2)) => f1 == f2, + (TypeEnum::Variable(i1, b1), TypeEnum::Variable(i2, b2)) => i1 == i2 && b1 == b2, + (TypeEnum::RowVar(v1), TypeEnum::RowVar(v2)) => v1.as_rv() == v2.as_rv(), + (TypeEnum::Sum(s1), TypeEnum::Sum(s2)) => s1 == s2, + _ => false, + } + } +} -impl Type { - /// An empty `TypeRow`. Provided here for convenience - pub const EMPTY_TYPEROW: TypeRow = type_row![]; +impl PartialEq> for TypeBase { + fn eq(&self, other: &TypeBase) -> bool { + self.0 == other.0 && self.1 == other.1 + } +} + +impl TypeBase { + /// An empty `TypeRow` or `TypeRowRV`. Provided here for convenience + pub const EMPTY_TYPEROW: TypeRowBase = TypeRowBase::::new(); /// Unit type (empty tuple). pub const UNIT: Self = Self(TypeEnum::Sum(SumType::Unit { size: 1 }), TypeBound::Eq); - const EMPTY_TYPEROW_REF: &'static TypeRow = &Self::EMPTY_TYPEROW; + const EMPTY_TYPEROW_REF: &'static TypeRowBase = &Self::EMPTY_TYPEROW; /// Initialize a new function type. - pub fn new_function(fun_ty: impl Into) -> Self { + pub fn new_function(fun_ty: impl Into) -> Self { Self::new(TypeEnum::Function(Box::new(fun_ty.into()))) } /// Initialize a new tuple type by providing the elements. #[inline(always)] - pub fn new_tuple(types: impl Into) -> Self { + pub fn new_tuple(types: impl Into) -> Self { let row = types.into(); match row.len() { 0 => Self::UNIT, @@ -314,7 +337,10 @@ impl Type { /// Initialize a new sum type by providing the possible variant types. #[inline(always)] - pub fn new_sum(variants: impl IntoIterator) -> Self where { + pub fn new_sum(variants: impl IntoIterator) -> Self + where + R: Into, + { Self::new(TypeEnum::Sum(SumType::new(variants))) } @@ -322,7 +348,7 @@ impl Type { // TODO remove? Extensions/TypeDefs should just provide `Type` directly pub const fn new_extension(opaque: CustomType) -> Self { let bound = opaque.bound(); - Type(TypeEnum::Extension(opaque), bound) + TypeBase(TypeEnum::Extension(opaque), bound) } /// Initialize a new alias. @@ -330,7 +356,7 @@ impl Type { Self::new(TypeEnum::Alias(alias)) } - fn new(type_e: TypeEnum) -> Self { + fn new(type_e: TypeEnum) -> Self { let bound = type_e.least_upper_bound(); Self(type_e, bound) } @@ -349,19 +375,6 @@ impl Type { Self(TypeEnum::Variable(idx, bound), bound) } - /// New use (occurrence) of the row variable with specified index. - /// `bound` must be exactly that with which the variable was declared - /// (i.e. as a [TypeParam::List]` of a `[TypeParam::Type]` of that bound), - /// which may be narrower than required for the use. - /// For use in [OpDef] type schemes, or function types, only, - /// not [FuncDefn] type schemes or as a Hugr port type. - /// - /// [OpDef]: crate::extension::OpDef - /// [FuncDefn]: crate::ops::FuncDefn - pub const fn new_row_var_use(idx: usize, bound: TypeBound) -> Self { - Self(TypeEnum::RowVariable(idx, bound), bound) - } - /// Report the least upper [TypeBound] #[inline(always)] pub const fn least_upper_bound(&self) -> TypeBound { @@ -370,7 +383,7 @@ impl Type { /// Report the component TypeEnum. #[inline(always)] - pub const fn as_type_enum(&self) -> &TypeEnum { + pub const fn as_type_enum(&self) -> &TypeEnum { &self.0 } @@ -380,11 +393,6 @@ impl Type { TypeBound::Copyable.contains(self.least_upper_bound()) } - /// Tells if this Type is a row variable, i.e. could stand for any number >=0 of Types - pub fn is_row_var(&self) -> bool { - matches!(self.0, TypeEnum::RowVariable(_, _)) - } - /// Checks all variables used in the type are in the provided list /// of bound variables, rejecting any [RowVariable]s if `allow_row_vars` is False; /// and that for each [CustomType] the corresponding @@ -396,7 +404,6 @@ impl Type { /// [TypeDef]: crate::extension::TypeDef pub(crate) fn validate( &self, - allow_row_vars: bool, extension_registry: &ExtensionRegistry, var_decls: &[TypeParam], ) -> Result<(), SignatureError> { @@ -405,21 +412,15 @@ impl Type { match &self.0 { TypeEnum::Sum(SumType::General { rows }) => rows .iter() - .try_for_each(|row| row.validate_var_len(extension_registry, var_decls)), + .try_for_each(|row| row.validate(extension_registry, var_decls)), TypeEnum::Sum(SumType::Unit { .. }) => Ok(()), // No leaves there TypeEnum::Alias(_) => Ok(()), TypeEnum::Extension(custy) => custy.validate(extension_registry, var_decls), // Function values may be passed around without knowing their arity // (i.e. with row vars) as long as they are not called: - TypeEnum::Function(ft) => ft.validate_var_len(extension_registry, var_decls), + TypeEnum::Function(ft) => ft.validate(extension_registry, var_decls), TypeEnum::Variable(idx, bound) => check_typevar_decl(var_decls, *idx, &(*bound).into()), - TypeEnum::RowVariable(idx, bound) => { - if allow_row_vars { - check_typevar_decl(var_decls, *idx, &TypeParam::new_list(*bound)) - } else { - Err(SignatureError::RowVarWhereTypeExpected { idx: *idx }) - } - } + TypeEnum::RowVar(rv) => rv.validate(var_decls), } } @@ -431,23 +432,94 @@ impl Type { /// return a Vec containing any number of [Type]s. These may (or not) pass [Type::validate] fn substitute(&self, t: &Substitution) -> Vec { match &self.0 { - TypeEnum::RowVariable(idx, bound) => t.apply_rowvar(*idx, *bound), + TypeEnum::RowVar(rv) => rv.substitute(t), TypeEnum::Alias(_) | TypeEnum::Sum(SumType::Unit { .. }) => vec![self.clone()], TypeEnum::Variable(idx, bound) => { let TypeArg::Type { ty } = t.apply_var(*idx, &((*bound).into())) else { panic!("Variable was not a type - try validate() first") }; - vec![ty] + vec![ty.into_()] } - TypeEnum::Extension(cty) => vec![Type::new_extension(cty.substitute(t))], - TypeEnum::Function(bf) => vec![Type::new_function(bf.substitute(t))], + TypeEnum::Extension(cty) => vec![TypeBase::new_extension(cty.substitute(t))], + TypeEnum::Function(bf) => vec![TypeBase::new_function(bf.substitute(t))], TypeEnum::Sum(SumType::General { rows }) => { - vec![Type::new_sum(rows.iter().map(|r| r.substitute(t)))] + vec![TypeBase::new_sum(rows.iter().map(|r| r.substitute(t)))] } } } } +impl Type { + fn substitute1(&self, s: &Substitution) -> Self { + let v = self.substitute(s); + let [r] = v.try_into().unwrap(); // No row vars, so every Type produces exactly one + r + } +} + +impl TypeRV { + /// Tells if this Type is a row variable, i.e. could stand for any number >=0 of Types + pub fn is_row_var(&self) -> bool { + matches!(self.0, TypeEnum::RowVar(_)) + } + + /// New use (occurrence) of the row variable with specified index. + /// `bound` must match that with which the variable was declared + /// (i.e. as a [TypeParam::List]` of a `[TypeParam::Type]` of that bound). + /// For use in [OpDef], not [FuncDefn], type schemes only. + /// + /// [OpDef]: crate::extension::OpDef + /// [FuncDefn]: crate::ops::FuncDefn + pub const fn new_row_var_use(idx: usize, bound: TypeBound) -> Self { + Self(TypeEnum::RowVar(RowVariable(idx, bound)), bound) + } +} + +// ====== Conversions ====== +impl TryFrom for Type { + type Error = RowVariable; + fn try_from(value: TypeRV) -> Result { + Ok(Self( + match value.0 { + TypeEnum::Extension(e) => TypeEnum::Extension(e), + TypeEnum::Alias(a) => TypeEnum::Alias(a), + TypeEnum::Function(f) => TypeEnum::Function(f), + TypeEnum::Variable(idx, bound) => TypeEnum::Variable(idx, bound), + TypeEnum::RowVar(rv) => return Err(rv.as_rv().clone()), + TypeEnum::Sum(s) => TypeEnum::Sum(s), + }, + value.1, + )) + } +} + +impl TypeBase { + /// A swiss-army-knife for any safe conversion of the type argument `RV1` + /// to/from [NoRV]/RowVariable/rust-type-variable. + fn into_(self) -> TypeBase + where + RV1: Into, + { + TypeBase( + match self.0 { + TypeEnum::Extension(e) => TypeEnum::Extension(e), + TypeEnum::Alias(a) => TypeEnum::Alias(a), + TypeEnum::Function(f) => TypeEnum::Function(f), + TypeEnum::Variable(idx, bound) => TypeEnum::Variable(idx, bound), + TypeEnum::RowVar(rv) => TypeEnum::RowVar(rv.into()), + TypeEnum::Sum(s) => TypeEnum::Sum(s), + }, + self.1, + ) + } +} + +impl From for TypeRV { + fn from(value: Type) -> Self { + value.into_() + } +} + /// Details a replacement of type variables with a finite list of known values. /// (Variables out of the range of the list will result in a panic) pub(crate) struct Substitution<'a>(&'a [TypeArg], &'a ExtensionRegistry); @@ -462,24 +534,31 @@ impl<'a> Substitution<'a> { arg.clone() } - fn apply_rowvar(&self, idx: usize, bound: TypeBound) -> Vec { + fn apply_rowvar(&self, idx: usize, bound: TypeBound) -> Vec { let arg = self .0 .get(idx) .expect("Undeclared type variable - call validate() ?"); debug_assert!(check_type_arg(arg, &TypeParam::new_list(bound)).is_ok()); match arg { - // Row variables are represented as 'TypeArg::Type's (see TypeArg::new_var_use) TypeArg::Sequence { elems } => elems .iter() - .map(|ta| match ta { - TypeArg::Type { ty } => ty.clone(), - _ => panic!("Not a list of types - call validate() ?"), + .map(|ta| { + match ta { + TypeArg::Type { ty } => return ty.clone().into(), + TypeArg::Variable { v } => { + if let Some(b) = v.bound_if_row_var() { + return TypeRV::new_row_var_use(v.index(), b); + } + } + _ => (), + } + panic!("Not a list of types - call validate() ?") }) .collect(), - TypeArg::Type { ty } if matches!(ty.0, TypeEnum::RowVariable(_, _)) => { + TypeArg::Type { ty } if matches!(ty.0, TypeEnum::RowVar(_)) => { // Standalone "Type" can be used iff its actually a Row Variable not an actual (single) Type - vec![ty.clone()] + vec![ty.clone().into()] } _ => panic!("Not a type or list of types - call validate() ?"), } @@ -519,14 +598,14 @@ pub(crate) fn check_typevar_decl( pub(crate) mod test { use super::*; - use crate::extension::prelude::USIZE_T; + use crate::type_row; #[test] fn construct() { let t: Type = Type::new_tuple(vec![ USIZE_T, - Type::new_function(FunctionType::new_endo(vec![])), + Type::new_function(Signature::new_endo(vec![])), Type::new_extension(CustomType::new( "my_custom", [], @@ -541,22 +620,23 @@ pub(crate) mod test { ); } - #[test] + #[rstest::rstest] fn sum_construct() { - let pred1 = Type::new_sum([Type::EMPTY_TYPEROW, Type::EMPTY_TYPEROW]); - let pred2 = Type::new_unit_sum(2); + let pred1 = Type::new_sum([type_row![], type_row![]]); + let pred2 = TypeRV::new_unit_sum(2); assert_eq!(pred1, pred2); let pred_direct = SumType::Unit { size: 2 }; - assert_eq!(pred1, pred_direct.into()) + assert_eq!(pred1, Type::from(pred_direct)); } mod proptest { use crate::proptest::RecursionDepth; - use crate::types::{SumType, TypeEnum, TypeRow}; + use super::{AliasDecl, MaybeRV, TypeBase, TypeBound, TypeEnum}; + use crate::types::{CustomType, FuncValueType, SumType, TypeRowRV}; use ::proptest::prelude::*; impl Arbitrary for super::SumType { @@ -567,28 +647,29 @@ pub(crate) mod test { if depth.leaf() { any::().prop_map(Self::new_unary).boxed() } else { - vec(any_with::(depth), 0..3) + vec(any_with::(depth), 0..3) .prop_map(SumType::new) .boxed() } } } - impl Arbitrary for super::Type { + impl Arbitrary for TypeBase { type Parameters = RecursionDepth; type Strategy = BoxedStrategy; fn arbitrary_with(depth: Self::Parameters) -> Self::Strategy { // We descend here, because a TypeEnum may contain a Type - any_with::(depth.descend()) - .prop_map(Self::new) - .boxed() - } - } - - impl super::Type { - pub fn any_non_row_var() -> BoxedStrategy { - any::() - .prop_filter("Cannot be a Row Variable", |t| !t.is_row_var()) + let depth = depth.descend(); + prop_oneof![ + 1 => any::().prop_map(TypeBase::new_alias), + 1 => any_with::(depth.into()).prop_map(TypeBase::new_extension), + 1 => any_with::(depth).prop_map(TypeBase::new_function), + 1 => any_with::(depth).prop_map(TypeBase::from), + 1 => (any::(), any::()).prop_map(|(i,b)| TypeBase::new_var_use(i,b)), + // proptest_derive::Arbitrary's weight attribute requires a constant, + // rather than this expression, hence the manual impl: + RV::weight() => RV::arb().prop_map(|rv| TypeBase::new(TypeEnum::RowVar(rv))) + ] .boxed() } } diff --git a/hugr-core/src/types/check.rs b/hugr-core/src/types/check.rs index 174ff817d..2146ee41b 100644 --- a/hugr-core/src/types/check.rs +++ b/hugr-core/src/types/check.rs @@ -2,8 +2,8 @@ use thiserror::Error; -use super::Type; -use crate::ops::Value; +use super::{Type, TypeRow}; +use crate::{extension::SignatureError, ops::Value}; /// Errors that arise from typechecking constants #[derive(Clone, Debug, PartialEq, Error)] @@ -21,6 +21,14 @@ pub enum SumTypeError { /// The value that was found. found: Value, }, + /// The type of the variant we were trying to convert into contained type variables + #[error("Sum variant #{tag} contained a variable #{varidx}")] + VariantNotConcrete { + /// The variant index + tag: usize, + /// The index (identifier) of the type-variable + varidx: usize, + }, /// The length of the sum value doesn't match the length of the variant of /// the sum type. #[error("Sum variant #{tag} should have length {expected}, but has length {found}")] @@ -60,6 +68,12 @@ impl super::SumType { tag, num_variants: self.num_variants(), })?; + let variant: TypeRow = variant.clone().try_into().map_err(|e| { + let SignatureError::RowVarWhereTypeExpected { var } = e else { + panic!("Unexpected error") + }; + SumTypeError::VariantNotConcrete { tag, varidx: var.0 } + })?; if variant.len() != val.len() { Err(SumTypeError::WrongVariantLength { diff --git a/hugr-core/src/types/poly_func.rs b/hugr-core/src/types/poly_func.rs index e152a3c60..70c60ed28 100644 --- a/hugr-core/src/types/poly_func.rs +++ b/hugr-core/src/types/poly_func.rs @@ -10,7 +10,8 @@ use { }; use super::type_param::{check_type_args, TypeArg, TypeParam}; -use super::{FunctionType, Substitution}; +use super::Substitution; +use super::{signature::FuncTypeBase, MaybeRV, NoRV, RowVariable}; /// A polymorphic type scheme, i.e. of a [FuncDecl], [FuncDefn] or [OpDef]. /// (Nodes/operations in the Hugr are not polymorphic.) @@ -19,7 +20,7 @@ use super::{FunctionType, Substitution}; /// [FuncDefn]: crate::ops::module::FuncDefn /// [OpDef]: crate::extension::OpDef #[derive( - Clone, PartialEq, Debug, Default, Eq, derive_more::Display, serde::Serialize, serde::Deserialize, + Clone, PartialEq, Debug, Eq, derive_more::Display, serde::Serialize, serde::Deserialize, )] #[cfg_attr(test, derive(Arbitrary), proptest(params = "RecursionDepth"))] #[display( @@ -27,19 +28,43 @@ use super::{FunctionType, Substitution}; "params.iter().map(ToString::to_string).join(\" \")", "body" )] -pub struct PolyFuncType { +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 /// defines the indices used by variables inside the body. #[cfg_attr(test, proptest(strategy = "vec(any_with::(params), 0..3)"))] params: Vec, /// Template for the function. May contain variables up to length of [Self::params] - #[cfg_attr(test, proptest(strategy = "any_with::(params)"))] - body: FunctionType, + #[cfg_attr(test, proptest(strategy = "any_with::>(params)"))] + body: FuncTypeBase, } -impl From for PolyFuncType { - fn from(body: FunctionType) -> Self { +/// The polymorphic type of a [Call]-able function ([FuncDecl] or [FuncDefn]). +/// Number of inputs and outputs fixed. +/// +/// [Call]: crate::ops::Call +/// [FuncDefn]: crate::ops::FuncDefn +/// [FuncDecl]: crate::ops::FuncDecl +pub type PolyFuncType = PolyFuncTypeBase; + +/// The polymorphic type of an [OpDef], whose number of input and outputs +/// may vary according to how [RowVariable]s therein are instantiated. +/// +/// [OpDef]: crate::extension::OpDef +pub type PolyFuncTypeRV = PolyFuncTypeBase; + +// deriving Default leads to an impl that only applies for RV: Default +impl Default for PolyFuncTypeBase { + fn default() -> Self { + Self { + params: Default::default(), + body: Default::default(), + } + } +} + +impl From> for PolyFuncTypeBase { + fn from(body: FuncTypeBase) -> Self { Self { params: vec![], body, @@ -47,11 +72,20 @@ impl From for PolyFuncType { } } -impl TryFrom for FunctionType { - /// If the PolyFuncType is not a monomorphic FunctionType, fail with the binders +impl From for PolyFuncTypeRV { + fn from(value: PolyFuncType) -> Self { + Self { + params: value.params, + body: value.body.into(), + } + } +} + +impl TryFrom> for FuncTypeBase { + /// If the PolyFuncTypeBase is not monomorphic, fail with its binders type Error = Vec; - fn try_from(value: PolyFuncType) -> Result { + fn try_from(value: PolyFuncTypeBase) -> Result { if value.params.is_empty() { Ok(value.body) } else { @@ -60,37 +94,27 @@ impl TryFrom for FunctionType { } } -impl PolyFuncType { +impl PolyFuncTypeBase { /// The type parameters, aka binders, over which this type is polymorphic pub fn params(&self) -> &[TypeParam] { &self.params } /// The body of the type, a function type. - pub fn body(&self) -> &FunctionType { + pub fn body(&self) -> &FuncTypeBase { &self.body } - /// Create a new PolyFuncType given the kinds of the variables it declares - /// and the underlying [FunctionType]. - pub fn new(params: impl Into>, body: FunctionType) -> Self { + /// Create a new PolyFuncTypeBase given the kinds of the variables it declares + /// and the underlying [FuncTypeBase]. + pub fn new(params: impl Into>, body: impl Into>) -> Self { Self { params: params.into(), - body, + body: body.into(), } } - /// Validates this instance, checking that the types in the body are - /// wellformed with respect to the registry, and the type variables declared. - /// Allows both inputs and outputs to contain [RowVariable]s - /// - /// [RowVariable]: [crate::types::TypeEnum::RowVariable] - pub fn validate_var_len(&self, reg: &ExtensionRegistry) -> Result<(), SignatureError> { - // TODO https://github.com/CQCL/hugr/issues/624 validate TypeParams declared here, too - self.body.validate_var_len(reg, &self.params) - } - - /// Instantiates an outer [PolyFuncType], i.e. with no free variables + /// Instantiates an outer [PolyFuncTypeBase], i.e. with no free variables /// (as ensured by [Self::validate]), into a monomorphic type. /// /// # Errors @@ -100,12 +124,19 @@ impl PolyFuncType { &self, args: &[TypeArg], ext_reg: &ExtensionRegistry, - ) -> Result { + ) -> Result, SignatureError> { // Check that args are applicable, and that we have a value for each binder, // i.e. each possible free variable within the body. check_type_args(args, &self.params)?; Ok(self.body.substitute(&Substitution(args, ext_reg))) } + + /// Validates this instance, checking that the types in the body are + /// wellformed with respect to the registry, and the type variables declared. + pub fn validate(&self, reg: &ExtensionRegistry) -> Result<(), SignatureError> { + // TODO https://github.com/CQCL/hugr/issues/624 validate TypeParams declared here, too + self.body.validate(reg, &self.params) + } } #[cfg(test)] @@ -121,25 +152,28 @@ pub(crate) mod test { PRELUDE_REGISTRY, }; use crate::std_extensions::collections::{EXTENSION, LIST_TYPENAME}; + use crate::types::signature::FuncTypeBase; use crate::types::type_param::{TypeArg, TypeArgError, TypeParam}; - use crate::types::{CustomType, FunctionType, Type, TypeBound, TypeName}; + use crate::types::{ + CustomType, FuncValueType, MaybeRV, Signature, Type, TypeBound, TypeName, TypeRV, + }; use crate::Extension; - use super::PolyFuncType; + use super::PolyFuncTypeBase; lazy_static! { static ref REGISTRY: ExtensionRegistry = ExtensionRegistry::try_new([PRELUDE.to_owned(), EXTENSION.to_owned()]).unwrap(); } - impl PolyFuncType { + impl PolyFuncTypeBase { fn new_validated( params: impl Into>, - body: FunctionType, + body: FuncTypeBase, extension_registry: &ExtensionRegistry, ) -> Result { let res = Self::new(params, body); - res.validate_var_len(extension_registry)?; + res.validate(extension_registry)?; Ok(res) } } @@ -149,16 +183,16 @@ pub(crate) mod test { let list_def = EXTENSION.get_type(&LIST_TYPENAME).unwrap(); let tyvar = TypeArg::new_var_use(0, TypeBound::Any.into()); let list_of_var = Type::new_extension(list_def.instantiate([tyvar.clone()])?); - let list_len = PolyFuncType::new_validated( + let list_len = PolyFuncTypeBase::new_validated( [TypeBound::Any.into()], - FunctionType::new(vec![list_of_var], vec![USIZE_T]), + Signature::new(vec![list_of_var], vec![USIZE_T]), ®ISTRY, )?; let t = list_len.instantiate(&[TypeArg::Type { ty: USIZE_T }], ®ISTRY)?; assert_eq!( t, - FunctionType::new( + Signature::new( vec![Type::new_extension( list_def .instantiate([TypeArg::Type { ty: USIZE_T }]) @@ -171,10 +205,6 @@ pub(crate) mod test { Ok(()) } - fn id_fn(t: Type) -> FunctionType { - FunctionType::new(vec![t.clone()], vec![t]) - } - #[test] fn test_mismatched_args() -> Result<(), SignatureError> { let ar_def = PRELUDE.get_type("array").unwrap(); @@ -184,8 +214,11 @@ pub(crate) mod test { // Valid schema... let good_array = Type::new_extension(ar_def.instantiate([tyvar.clone(), szvar.clone()])?); - let good_ts = - PolyFuncType::new_validated(typarams.clone(), id_fn(good_array), &PRELUDE_REGISTRY)?; + let good_ts = PolyFuncTypeBase::new_validated( + typarams.clone(), + Signature::new_endo(good_array), + &PRELUDE_REGISTRY, + )?; // Sanity check (good args) good_ts.instantiate( @@ -223,8 +256,11 @@ pub(crate) mod test { PRELUDE_ID, TypeBound::Any, )); - let bad_ts = - PolyFuncType::new_validated(typarams.clone(), id_fn(bad_array), &PRELUDE_REGISTRY); + let bad_ts = PolyFuncTypeBase::new_validated( + typarams.clone(), + Signature::new_endo(bad_array), + &PRELUDE_REGISTRY, + ); assert_eq!(bad_ts.err(), Some(arg_err)); Ok(()) @@ -235,7 +271,7 @@ pub(crate) mod test { // Variables in args have different bounds from variable declaration let tv = TypeArg::new_var_use(0, TypeBound::Copyable.into()); let list_def = EXTENSION.get_type(&LIST_TYPENAME).unwrap(); - let body_type = id_fn(Type::new_extension(list_def.instantiate([tv])?)); + let body_type = Signature::new_endo(Type::new_extension(list_def.instantiate([tv])?)); for decl in [ TypeParam::Extensions, TypeParam::List { @@ -247,7 +283,7 @@ pub(crate) mod test { }, ] { let invalid_ts = - PolyFuncType::new_validated([decl.clone()], body_type.clone(), ®ISTRY); + PolyFuncTypeBase::new_validated([decl.clone()], body_type.clone(), ®ISTRY); assert_eq!( invalid_ts.err(), Some(SignatureError::TypeVarDoesNotMatchDeclaration { @@ -257,7 +293,7 @@ pub(crate) mod test { ); } // Variable not declared at all - let invalid_ts = PolyFuncType::new_validated([], body_type, ®ISTRY); + let invalid_ts = PolyFuncTypeBase::new_validated([], body_type, ®ISTRY); assert_eq!( invalid_ts.err(), Some(SignatureError::FreeTypeVar { @@ -289,9 +325,9 @@ pub(crate) mod test { let reg = ExtensionRegistry::try_new([e]).unwrap(); let make_scheme = |tp: TypeParam| { - PolyFuncType::new_validated( + PolyFuncTypeBase::new_validated( [tp.clone()], - id_fn(Type::new_extension(CustomType::new( + Signature::new_endo(Type::new_extension(CustomType::new( TYPE_NAME, [TypeArg::new_var_use(0, tp)], EXT_ID, @@ -354,11 +390,11 @@ pub(crate) mod test { let decl = TypeParam::List { param: Box::new(TP_ANY), }; - let e = PolyFuncType::new_validated( + let e = PolyFuncTypeBase::new_validated( [decl.clone()], - FunctionType::new( + FuncValueType::new( vec![USIZE_T], - vec![Type::new_row_var_use(0, TypeBound::Copyable)], + vec![TypeRV::new_row_var_use(0, TypeBound::Copyable)], ), &PRELUDE_REGISTRY, ) @@ -368,9 +404,9 @@ pub(crate) mod test { assert_eq!(cached, TypeParam::List {param: Box::new(TypeParam::Type {b: TypeBound::Copyable})}); }); // Declared as row variable, used as type variable - let e = PolyFuncType::new_validated( + let e = PolyFuncTypeBase::new_validated( [decl.clone()], - FunctionType::new_endo(vec![Type::new_var_use(0, TypeBound::Any)]), + Signature::new_endo(vec![Type::new_var_use(0, TypeBound::Any)]), &EMPTY_REG, ) .unwrap_err(); @@ -382,10 +418,13 @@ pub(crate) mod test { #[test] fn row_variables() { - let rty = Type::new_row_var_use(0, TypeBound::Any); - let pf = PolyFuncType::new_validated( + let rty = TypeRV::new_row_var_use(0, TypeBound::Any); + let pf = PolyFuncTypeBase::new_validated( [TypeParam::new_list(TP_ANY)], - FunctionType::new(vec![USIZE_T, rty.clone()], vec![Type::new_tuple(rty)]), + FuncValueType::new( + vec![USIZE_T.into(), rty.clone()], + vec![TypeRV::new_tuple(rty)], + ), &PRELUDE_REGISTRY, ) .unwrap(); @@ -408,7 +447,7 @@ pub(crate) mod test { .unwrap(); assert_eq!( t2, - FunctionType::new( + Signature::new( vec![USIZE_T, USIZE_T, BOOL_T], vec![Type::new_tuple(vec![USIZE_T, BOOL_T])] ) @@ -417,22 +456,22 @@ pub(crate) mod test { #[test] fn row_variables_inner() { - let inner_fty = Type::new_function(FunctionType::new_endo(vec![Type::new_row_var_use( + let inner_fty = Type::new_function(FuncValueType::new_endo(TypeRV::new_row_var_use( 0, TypeBound::Copyable, - )])); - let pf = PolyFuncType::new_validated( + ))); + let pf = PolyFuncTypeBase::new_validated( [TypeParam::List { param: Box::new(TypeParam::Type { b: TypeBound::Copyable, }), }], - FunctionType::new(vec![USIZE_T, inner_fty.clone()], vec![inner_fty]), + Signature::new(vec![USIZE_T, inner_fty.clone()], vec![inner_fty]), &PRELUDE_REGISTRY, ) .unwrap(); - let inner3 = Type::new_function(FunctionType::new_endo(vec![USIZE_T, BOOL_T, USIZE_T])); + let inner3 = Type::new_function(Signature::new_endo(vec![USIZE_T, BOOL_T, USIZE_T])); let t3 = pf .instantiate( &[TypeArg::Sequence { @@ -443,7 +482,7 @@ pub(crate) mod test { .unwrap(); assert_eq!( t3, - FunctionType::new(vec![USIZE_T, inner3.clone()], vec![inner3]) + Signature::new(vec![USIZE_T, inner3.clone()], vec![inner3]) ); } } diff --git a/hugr-core/src/types/row_var.rs b/hugr-core/src/types/row_var.rs new file mode 100644 index 000000000..9efc2e12f --- /dev/null +++ b/hugr-core/src/types/row_var.rs @@ -0,0 +1,126 @@ +//! Classes for row variables (i.e. Type variables that can stand for multiple types) + +use super::type_param::TypeParam; +use super::{check_typevar_decl, Substitution, TypeBase, TypeBound}; +use crate::extension::SignatureError; + +#[cfg(test)] +use proptest::prelude::{any, BoxedStrategy, Strategy}; +/// Describes a row variable - a type variable bound with a [TypeParam::List] of [TypeParam::Type] +/// of the specified bound (checked in validation) +// The serde derives here are not used except as markers +// so that other types containing this can also #derive-serde the same way. +#[derive( + Clone, Debug, Eq, PartialEq, derive_more::Display, serde::Serialize, serde::Deserialize, +)] +#[display(fmt = "{}", "_0")] +pub struct RowVariable(pub usize, pub TypeBound); + +// Note that whilst 'pub' this is not re-exported outside private module `row_var` +// so is effectively sealed. +pub trait MaybeRV: + Clone + + std::fmt::Debug + + std::fmt::Display + + From + + Into + + Eq + + PartialEq + + 'static +{ + fn as_rv(&self) -> &RowVariable; + fn try_from_rv(rv: RowVariable) -> Result; + fn bound(&self) -> TypeBound; + fn validate(&self, var_decls: &[TypeParam]) -> Result<(), SignatureError>; + #[allow(private_interfaces)] + fn substitute(&self, s: &Substitution) -> Vec>; + #[cfg(test)] + fn weight() -> u32 { + 1 + } + #[cfg(test)] + fn arb() -> BoxedStrategy; +} + +/// Has no instances - used as parameter to [Type] to rule out the possibility +/// of there being any [TypeEnum::RowVar]s +/// +/// [TypeEnum::RowVar]: super::TypeEnum::RowVar +/// [Type]: super::Type +// The serde derives here are not used except as markers +// so that other types containing this can also #derive-serde the same way. +#[derive( + Clone, Debug, Eq, PartialEq, derive_more::Display, serde::Serialize, serde::Deserialize, +)] +pub enum NoRV {} + +impl From for RowVariable { + fn from(value: NoRV) -> Self { + match value {} + } +} + +impl MaybeRV for RowVariable { + fn as_rv(&self) -> &RowVariable { + self + } + + fn bound(&self) -> TypeBound { + self.1 + } + + fn validate(&self, var_decls: &[TypeParam]) -> Result<(), SignatureError> { + check_typevar_decl(var_decls, self.0, &TypeParam::new_list(self.1)) + } + + #[allow(private_interfaces)] + fn substitute(&self, s: &Substitution) -> Vec> { + s.apply_rowvar(self.0, self.1) + } + + fn try_from_rv(rv: RowVariable) -> Result { + Ok(rv) + } + + #[cfg(test)] + fn arb() -> BoxedStrategy { + (any::(), any::()) + .prop_map(|(i, b)| Self(i, b)) + .boxed() + } +} + +impl MaybeRV for NoRV { + fn as_rv(&self) -> &RowVariable { + match *self {} + } + + fn bound(&self) -> TypeBound { + match *self {} + } + + fn validate(&self, _var_decls: &[TypeParam]) -> Result<(), SignatureError> { + match *self {} + } + + #[allow(private_interfaces)] + fn substitute(&self, _s: &Substitution) -> Vec> { + match *self {} + } + + fn try_from_rv(rv: RowVariable) -> Result { + Err(rv) + } + + #[cfg(test)] + fn weight() -> u32 { + 0 + } + + #[cfg(test)] + fn arb() -> BoxedStrategy { + any::() + .prop_map(|_| panic!("Should be ruled out by weight==0")) + .boxed() + } +} diff --git a/hugr-core/src/types/serialize.rs b/hugr-core/src/types/serialize.rs index e4585d2f5..de1f94da1 100644 --- a/hugr-core/src/types/serialize.rs +++ b/hugr-core/src/types/serialize.rs @@ -1,8 +1,9 @@ -use super::{FunctionType, SumType, Type, TypeArg, TypeBound, TypeEnum}; +use super::{FuncValueType, MaybeRV, RowVariable, SumType, TypeArg, TypeBase, TypeBound, TypeEnum}; use super::custom::CustomType; use crate::extension::prelude::{array_type, QB_T, USIZE_T}; +use crate::extension::SignatureError; use crate::ops::AliasDecl; #[derive(serde::Serialize, serde::Deserialize, Clone, Debug)] @@ -10,7 +11,7 @@ use crate::ops::AliasDecl; pub(super) enum SerSimpleType { Q, I, - G(Box), + G(Box), Sum(SumType), Array { inner: Box, len: u64 }, Opaque(CustomType), @@ -19,41 +20,47 @@ pub(super) enum SerSimpleType { R { i: usize, b: TypeBound }, } -impl From for SerSimpleType { - fn from(value: Type) -> Self { +impl From> for SerSimpleType { + fn from(value: TypeBase) -> Self { if value == QB_T { return SerSimpleType::Q; - } + }; if value == USIZE_T { return SerSimpleType::I; - } - // TODO short circuiting for array. - let Type(value, _) = value; - match value { + }; + match value.0 { TypeEnum::Extension(o) => SerSimpleType::Opaque(o), TypeEnum::Alias(a) => SerSimpleType::Alias(a), TypeEnum::Function(sig) => SerSimpleType::G(sig), TypeEnum::Variable(i, b) => SerSimpleType::V { i, b }, - TypeEnum::RowVariable(i, b) => SerSimpleType::R { i, b }, + TypeEnum::RowVar(rv) => { + let RowVariable(idx, bound) = rv.as_rv(); + SerSimpleType::R { i: *idx, b: *bound } + } TypeEnum::Sum(st) => SerSimpleType::Sum(st), } } } -impl From for Type { - fn from(value: SerSimpleType) -> Type { - match value { - SerSimpleType::Q => QB_T, - SerSimpleType::I => USIZE_T, - SerSimpleType::G(sig) => Type::new_function(*sig), +impl TryFrom for TypeBase { + type Error = SignatureError; + fn try_from(value: SerSimpleType) -> Result { + Ok(match value { + SerSimpleType::Q => QB_T.into_(), + SerSimpleType::I => USIZE_T.into_(), + SerSimpleType::G(sig) => TypeBase::new_function(*sig), SerSimpleType::Sum(st) => st.into(), SerSimpleType::Array { inner, len } => { - array_type(TypeArg::BoundedNat { n: len }, (*inner).into()) + array_type(TypeArg::BoundedNat { n: len }, (*inner).try_into().unwrap()).into_() } - SerSimpleType::Opaque(o) => Type::new_extension(o), - SerSimpleType::Alias(a) => Type::new_alias(a), - SerSimpleType::V { i, b } => Type::new_var_use(i, b), - SerSimpleType::R { i, b } => Type::new_row_var_use(i, b), - } + SerSimpleType::Opaque(o) => TypeBase::new_extension(o), + SerSimpleType::Alias(a) => TypeBase::new_alias(a), + SerSimpleType::V { i, b } => TypeBase::new_var_use(i, b), + // We can't use new_row_var because that returns TypeRV not TypeBase. + SerSimpleType::R { i, b } => TypeBase::new(TypeEnum::RowVar( + RV::try_from_rv(RowVariable(i, b)) + .map_err(|var| SignatureError::RowVarWhereTypeExpected { var })?, + )), + }) } } diff --git a/hugr-core/src/types/signature.rs b/hugr-core/src/types/signature.rs index 1cf731eda..74621be37 100644 --- a/hugr-core/src/types/signature.rs +++ b/hugr-core/src/types/signature.rs @@ -5,7 +5,8 @@ use itertools::Either; use std::fmt::{self, Display, Write}; use super::type_param::TypeParam; -use super::{Substitution, Type, TypeBound, TypeEnum, TypeRow}; +use super::type_row::TypeRowBase; +use super::{MaybeRV, NoRV, RowVariable, Substitution, Type, TypeRow}; use crate::core::PortIndex; use crate::extension::{ExtensionRegistry, ExtensionSet, SignatureError}; @@ -14,75 +15,122 @@ use crate::{Direction, IncomingPort, OutgoingPort, Port}; #[cfg(test)] use {crate::proptest::RecursionDepth, ::proptest::prelude::*, proptest_derive::Arbitrary}; -#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[derive(Clone, Debug, Eq, serde::Serialize, serde::Deserialize)] #[cfg_attr(test, derive(Arbitrary), proptest(params = "RecursionDepth"))] -/// Describes the edges required to/from a node, and thus, also the type of a [Graph]. -/// This includes both the concept of "signature" in the spec, -/// and also the target (value) of a call (static). +/// Describes the edges required to/from a node or inside a [FuncDefn] (when ROWVARS=[NoRV]); +/// or (when ROWVARS=[RowVariable]) the type of a higher-order [function value] or the inputs/outputs from an OpDef /// -/// [Graph]: crate::ops::constant::Value::Function -pub struct FunctionType { +/// ROWVARS specifies whether it may contain [RowVariable]s or not. +/// +/// [function value]: crate::ops::constant::Value::Function +/// [FuncDefn]: crate::ops::FuncDefn +pub struct FuncTypeBase { /// Value inputs of the function. - #[cfg_attr(test, proptest(strategy = "any_with::(params)"))] - pub input: TypeRow, + #[cfg_attr(test, proptest(strategy = "any_with::>(params)"))] + pub input: TypeRowBase, /// Value outputs of the function. - #[cfg_attr(test, proptest(strategy = "any_with::(params)"))] - pub output: TypeRow, + #[cfg_attr(test, proptest(strategy = "any_with::>(params)"))] + pub output: TypeRowBase, /// The extension requirements which are added by the operation pub extension_reqs: ExtensionSet, } -impl FunctionType { +/// The concept of "signature" in the spec - the edges required to/from a node +/// or within a [FuncDefn], also the target (value) of a call (static). +/// +/// [FuncDefn]: crate::ops::FuncDefn +pub type Signature = FuncTypeBase; + +/// A function that may contain [RowVariable]s and thus has potentially-unknown arity; +/// used for [OpDef]'s and passable as a value round a Hugr (see [Type::new_function]) +/// but not a valid node type. +/// +/// [OpDef]: crate::extension::OpDef +pub type FuncValueType = FuncTypeBase; + +impl FuncTypeBase { /// Builder method, add extension_reqs to an FunctionType pub fn with_extension_delta(mut self, rs: impl Into) -> Self { self.extension_reqs = self.extension_reqs.union(rs.into()); self } - pub(super) fn validate_var_len( - &self, - extension_registry: &ExtensionRegistry, - var_decls: &[TypeParam], - ) -> Result<(), SignatureError> { - self.input.validate_var_len(extension_registry, var_decls)?; - self.output - .validate_var_len(extension_registry, var_decls)?; - self.extension_reqs.validate(var_decls) - } - pub(crate) fn substitute(&self, tr: &Substitution) -> Self { - FunctionType { + Self { input: self.input.substitute(tr), output: self.output.substitute(tr), extension_reqs: self.extension_reqs.substitute(tr), } } -} - -impl FunctionType { - /// The number of wires in the signature. - #[inline(always)] - pub fn is_empty(&self) -> bool { - self.input.is_empty() && self.output.is_empty() - } -} -impl FunctionType { /// Create a new signature with specified inputs and outputs. - pub fn new(input: impl Into, output: impl Into) -> Self { + pub fn new(input: impl Into>, output: impl Into>) -> Self { Self { input: input.into(), output: output.into(), extension_reqs: ExtensionSet::new(), } } + /// Create a new signature with the same input and output types (signature of an endomorphic /// function). - pub fn new_endo(linear: impl Into) -> Self { - let linear = linear.into(); - Self::new(linear.clone(), linear) + pub fn new_endo(row: impl Into>) -> Self { + let row = row.into(); + Self::new(row.clone(), row) + } + + /// True if both inputs and outputs are necessarily empty. + /// (For [FuncValueType], even after any possible substitution of row variables) + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.input.is_empty() && self.output.is_empty() + } + + #[inline] + /// Returns a row of the value inputs of the function. + pub fn input(&self) -> &TypeRowBase { + &self.input } + #[inline] + /// Returns a row of the value outputs of the function. + pub fn output(&self) -> &TypeRowBase { + &self.output + } + + pub(super) fn validate( + &self, + extension_registry: &ExtensionRegistry, + var_decls: &[TypeParam], + ) -> Result<(), SignatureError> { + self.input.validate(extension_registry, var_decls)?; + self.output.validate(extension_registry, var_decls)?; + self.extension_reqs.validate(var_decls) + } +} + +impl FuncValueType { + /// If this FuncValueType contains any row variables, return one. + pub fn find_rowvar(&self) -> Option { + self.input + .iter() + .chain(self.output.iter()) + .find_map(|t| Type::try_from(t.clone()).err()) + } +} + +// deriving Default leads to an impl that only applies for RV: Default +impl Default for FuncTypeBase { + fn default() -> Self { + Self { + input: Default::default(), + output: Default::default(), + extension_reqs: Default::default(), + } + } +} + +impl Signature { /// Returns the type of a value [`Port`]. Returns `None` if the port is out /// of bounds. #[inline] @@ -98,7 +146,6 @@ impl FunctionType { /// of bounds. #[inline] pub fn in_port_type(&self, port: impl Into) -> Option<&Type> { - debug_assert!(self.find_rowvar().is_none()); self.input.get(port.into().index()) } @@ -106,7 +153,6 @@ impl FunctionType { /// of bounds. #[inline] pub fn out_port_type(&self, port: impl Into) -> Option<&Type> { - debug_assert!(self.find_rowvar().is_none()); self.output.get(port.into().index()) } @@ -114,7 +160,6 @@ impl FunctionType { /// of bounds. #[inline] pub fn in_port_type_mut(&mut self, port: impl Into) -> Option<&mut Type> { - debug_assert!(self.find_rowvar().is_none()); self.input.get_mut(port.into().index()) } @@ -122,7 +167,6 @@ impl FunctionType { /// of bounds. #[inline] pub fn out_port_type_mut(&mut self, port: impl Into) -> Option<&mut Type> { - debug_assert!(self.find_rowvar().is_none()); self.output.get_mut(port.into().index()) } @@ -179,31 +223,6 @@ impl FunctionType { self.types(Direction::Outgoing) } - #[inline] - /// Returns the input row - pub fn input(&self) -> &TypeRow { - &self.input - } - - #[inline] - /// Returns the output row - pub fn output(&self) -> &TypeRow { - &self.output - } -} - -impl FunctionType { - /// If this FunctionType contains any row variables, return one. - pub fn find_rowvar(&self) -> Option<(usize, TypeBound)> { - self.input - .iter() - .chain(self.output.iter()) - .find_map(|t| match t.0 { - TypeEnum::RowVariable(idx, bound) => Some((idx, bound)), - _ => None, - }) - } - /// Returns the `Port`s in the signature for a given direction. #[inline] pub fn ports(&self, dir: Direction) -> impl Iterator { @@ -225,7 +244,7 @@ impl FunctionType { } } -impl Display for FunctionType { +impl Display for FuncTypeBase { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if !self.input.is_empty() { self.input.fmt(f)?; @@ -238,6 +257,34 @@ impl Display for FunctionType { } } +impl TryFrom for Signature { + type Error = SignatureError; + + fn try_from(value: FuncValueType) -> Result { + let input: TypeRow = value.input.try_into()?; + let output: TypeRow = value.output.try_into()?; + Ok(Self::new(input, output).with_extension_delta(value.extension_reqs)) + } +} + +impl From for FuncValueType { + fn from(value: Signature) -> Self { + Self { + input: value.input.into(), + output: value.output.into(), + extension_reqs: value.extension_reqs, + } + } +} + +impl PartialEq> for FuncTypeBase { + fn eq(&self, other: &FuncTypeBase) -> bool { + self.input == other.input + && self.output == other.output + && self.extension_reqs == other.extension_reqs + } +} + #[cfg(test)] mod test { use crate::{extension::prelude::USIZE_T, type_row}; @@ -245,7 +292,7 @@ mod test { use super::*; #[test] fn test_function_type() { - let mut f_type = FunctionType::new(type_row![Type::UNIT], type_row![Type::UNIT]); + let mut f_type = Signature::new(type_row![Type::UNIT], type_row![Type::UNIT]); assert_eq!(f_type.input_count(), 1); assert_eq!(f_type.output_count(), 1); diff --git a/hugr-core/src/types/type_param.rs b/hugr-core/src/types/type_param.rs index b16e1f950..bfc5c04e3 100644 --- a/hugr-core/src/types/type_param.rs +++ b/hugr-core/src/types/type_param.rs @@ -14,7 +14,7 @@ use crate::extension::ExtensionRegistry; use crate::extension::ExtensionSet; use crate::extension::SignatureError; -use super::{check_typevar_decl, CustomType, Substitution, Type, TypeBound}; +use super::{check_typevar_decl, CustomType, RowVariable, Substitution, Type, TypeBound, TypeRV}; /// The upper non-inclusive bound of a [`TypeParam::BoundedNat`] // A None inner value implies the maximum bound: u64::MAX + 1 (all u64 values valid) @@ -46,11 +46,11 @@ impl UpperBound { } } -/// A *kind* of [TypeArg]. Thus, a parameter declared by a [PolyFuncType] (e.g. [OpDef]), -/// specifying a value that may (resp. must) be provided to instantiate it. +/// A *kind* of [TypeArg]. Thus, a parameter declared by a [PolyFuncType] or [PolyFuncTypeRV], +/// specifying a value that must be provided statically in order to instantiate it. /// /// [PolyFuncType]: super::PolyFuncType -/// [OpDef]: crate::extension::OpDef +/// [PolyFuncTypeRV]: super::PolyFuncTypeRV #[derive( Clone, Debug, PartialEq, Eq, derive_more::Display, serde::Deserialize, serde::Serialize, )] @@ -185,7 +185,16 @@ pub enum TypeArg { impl From for TypeArg { fn from(ty: Type) -> Self { - Self::Type { ty } + TypeArg::Type { ty } + } +} + +impl From for TypeArg { + fn from(value: TypeRV) -> Self { + match value.try_into() { + Ok(ty) => TypeArg::Type { ty }, + Err(RowVariable(idx, bound)) => TypeArg::new_var_use(idx, TypeParam::new_list(bound)), + } } } @@ -213,7 +222,9 @@ impl From for TypeArg { } } -/// Variable in a TypeArg, that is not a [TypeArg::Type] or [TypeArg::Extensions], +/// Variable in a TypeArg, that is neither a [TypeArg::Extensions] +/// nor a single [TypeArg::Type] (i.e. not a [Type::new_var_use] +/// - it might be a [Type::new_row_var_use]). #[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)] pub struct TypeArgVariable { idx: usize, @@ -221,22 +232,19 @@ pub struct TypeArgVariable { } impl TypeArg { + /// [Type::UNIT] as a [TypeArg::Type] + pub const UNIT: Self = Self::Type { ty: Type::UNIT }; + /// Makes a TypeArg representing a use (occurrence) of the type variable /// with the specified index. /// `decl` must be exactly that with which the variable was declared. pub fn new_var_use(idx: usize, decl: TypeParam) -> Self { match decl { + // Note a TypeParam::List of TypeParam::Type *cannot* be represented + // as a TypeArg::Type because the latter stores a Type i.e. only a single type, + // not a RowVariable. TypeParam::Type { b } => Type::new_var_use(idx, b).into(), - TypeParam::List { param: bx } if matches!(*bx, TypeParam::Type { .. }) => { - // There are two reasonable schemes for representing row variables: - // 1. TypeArg::Variable(idx, TypeParam::List(TypeParam::Type(typebound))) - // 2. TypeArg::Type(Type::new_row_var_use(idx, typebound)) - // Here we prefer the latter for canonicalization: TypeArgVariable's fields are non-pub - // so this prevents constructing malformed cases like the former. - let TypeParam::Type { b } = *bx else { panic!() }; - Type::new_row_var_use(idx, b).into() - } - // Similarly, prevent TypeArg::Variable(idx, TypeParam::Extensions) + // Prevent TypeArg::Variable(idx, TypeParam::Extensions) TypeParam::Extensions => TypeArg::Extensions { es: ExtensionSet::type_var(idx), }, @@ -257,8 +265,7 @@ impl TypeArg { var_decls: &[TypeParam], ) -> Result<(), SignatureError> { match self { - // Row variables are represented as 'TypeArg::Type's (see TypeArg::new_var_use) - TypeArg::Type { ty } => ty.validate(true, extension_registry, var_decls), + TypeArg::Type { ty } => ty.validate(extension_registry, var_decls), TypeArg::BoundedNat { .. } => Ok(()), TypeArg::Opaque { arg: custarg } => { // We could also add a facility to Extension to validate that the constant *value* @@ -275,12 +282,7 @@ impl TypeArg { v: TypeArgVariable { idx, cached_decl }, } => { assert!( - match cached_decl { - TypeParam::Type { .. } => false, - TypeParam::List { param } if matches!(**param, TypeParam::Type { .. }) => - false, - _ => true, - }, + !matches!(cached_decl, TypeParam::Type { .. }), "Malformed TypeArg::Variable {} - should be inconstructible", cached_decl ); @@ -293,14 +295,8 @@ impl TypeArg { pub(crate) fn substitute(&self, t: &Substitution) -> Self { match self { TypeArg::Type { ty } => { - let tys = ty.substitute(t).into_iter().map_into().collect::>(); - match as TryInto<[TypeArg; 1]>>::try_into(tys) { - Ok([ty]) => ty, - // Multiple elements can only have come from a row variable. - // So, we must be either in a TypeArg::Sequence; or a single Row Variable - // - fitting into a hole declared as a TypeParam::List (as per check_type_arg). - Err(elems) => TypeArg::Sequence { elems }, - } + // RowVariables are represented as TypeArg::Variable + ty.substitute1(t).into() } TypeArg::BoundedNat { .. } => self.clone(), // We do not allow variables as bounds on BoundedNat's TypeArg::Opaque { @@ -312,7 +308,11 @@ impl TypeArg { self.clone() } TypeArg::Sequence { elems } => { - let mut are_types = elems.iter().map(|e| matches!(e, TypeArg::Type { .. })); + let mut are_types = elems.iter().map(|ta| match ta { + TypeArg::Type { .. } => true, + TypeArg::Variable { v } => v.bound_if_row_var().is_some(), + _ => false, + }); let elems = match are_types.next() { Some(true) => { assert!(are_types.all(|b| b)); // If one is a Type, so must the rest be @@ -348,6 +348,17 @@ impl TypeArgVariable { pub fn index(&self) -> usize { self.idx } + + /// Determines whether this represents a row variable; if so, returns + /// the [TypeBound] of the individual types it might stand for. + pub fn bound_if_row_var(&self) -> Option { + if let TypeParam::List { param } = &self.cached_decl { + if let TypeParam::Type { b } = **param { + return Some(b); + } + } + None + } } /// A serialized representation of a value of a [CustomType] @@ -383,29 +394,25 @@ pub fn check_type_arg(arg: &TypeArg, param: &TypeParam) -> Result<(), TypeArgErr _, ) if param.contains(cached_decl) => Ok(()), (TypeArg::Type { ty }, TypeParam::Type { b: bound }) - if bound.contains(ty.least_upper_bound()) && !ty.is_row_var() => + if bound.contains(ty.least_upper_bound()) => { Ok(()) } (TypeArg::Sequence { elems }, TypeParam::List { param }) => { elems.iter().try_for_each(|arg| { // Also allow elements that are RowVars if fitting into a List of Types - if let (TypeArg::Type { ty }, TypeParam::Type { b }) = (arg, &**param) { - if ty.is_row_var() && b.contains(ty.least_upper_bound()) { + if let (TypeArg::Variable { v }, TypeParam::Type { b: param_bound }) = + (arg, &**param) + { + if v.bound_if_row_var() + .is_some_and(|arg_bound| param_bound.contains(arg_bound)) + { return Ok(()); } } check_type_arg(arg, param) }) } - // Also allow a single "Type" to be used for a List *only* if the Type is a row variable - // (i.e., it's not really a Type, it's multiple Types) - (TypeArg::Type { ty }, TypeParam::List { param }) - if ty.is_row_var() && param.contains(&ty.least_upper_bound().into()) => - { - Ok(()) - } - (TypeArg::Sequence { elems: items }, TypeParam::Tuple { params: types }) => { if items.len() != types.len() { Err(TypeArgError::WrongNumberTuple(items.len(), types.len())) @@ -479,11 +486,11 @@ mod test { use super::{check_type_arg, Substitution, TypeArg, TypeParam}; use crate::extension::prelude::{BOOL_T, PRELUDE_REGISTRY, USIZE_T}; - use crate::types::{type_param::TypeArgError, Type, TypeBound}; + use crate::types::{type_param::TypeArgError, TypeBound, TypeRV}; #[test] fn type_arg_fits_param() { - let rowvar = Type::new_row_var_use; + let rowvar = TypeRV::new_row_var_use; fn check(arg: impl Into, param: &TypeParam) -> Result<(), TypeArgError> { check_type_arg(&arg.into(), param) } @@ -506,13 +513,21 @@ mod test { check(vec![], &seq_param).unwrap(); check_seq(&[rowvar(0, TypeBound::Eq)], &seq_param).unwrap(); check_seq( - &[rowvar(1, TypeBound::Any), USIZE_T, rowvar(0, TypeBound::Eq)], + &[ + rowvar(1, TypeBound::Any), + USIZE_T.into(), + rowvar(0, TypeBound::Eq), + ], &TypeParam::new_list(TypeBound::Any), ) .unwrap(); // Next one fails because a list of Eq is required check_seq( - &[rowvar(1, TypeBound::Any), USIZE_T, rowvar(0, TypeBound::Eq)], + &[ + rowvar(1, TypeBound::Any), + USIZE_T.into(), + rowvar(0, TypeBound::Eq), + ], &seq_param, ) .unwrap_err(); @@ -554,7 +569,7 @@ mod test { #[test] fn type_arg_subst_row() { let row_param = TypeParam::new_list(TypeBound::Copyable); - let row_arg: TypeArg = vec![BOOL_T.into(), Type::UNIT.into()].into(); + let row_arg: TypeArg = vec![BOOL_T.into(), TypeArg::UNIT].into(); check_type_arg(&row_arg, &row_param).unwrap(); // Now say a row variable referring to *that* row was used @@ -562,7 +577,7 @@ mod test { let outer_param = TypeParam::new_list(TypeBound::Any); let outer_arg = TypeArg::Sequence { elems: vec![ - Type::new_row_var_use(0, TypeBound::Copyable).into(), + TypeRV::new_row_var_use(0, TypeBound::Copyable).into(), USIZE_T.into(), ], }; @@ -571,7 +586,7 @@ mod test { let outer_arg2 = outer_arg.substitute(&Substitution(&[row_arg], &PRELUDE_REGISTRY)); assert_eq!( outer_arg2, - vec![BOOL_T.into(), Type::UNIT.into(), USIZE_T.into()].into() + vec![BOOL_T.into(), TypeArg::UNIT, USIZE_T.into()].into() ); // Of course this is still valid (as substitution is guaranteed to preserve validity) diff --git a/hugr-core/src/types/type_row.rs b/hugr-core/src/types/type_row.rs index 5be3ddc2f..ec510fc28 100644 --- a/hugr-core/src/types/type_row.rs +++ b/hugr-core/src/types/type_row.rs @@ -7,7 +7,7 @@ use std::{ ops::{Deref, DerefMut}, }; -use super::{type_param::TypeParam, Substitution, Type}; +use super::{type_param::TypeParam, MaybeRV, NoRV, RowVariable, Substitution, Type, TypeBase}; use crate::{ extension::{ExtensionRegistry, SignatureError}, utils::display_list, @@ -16,15 +16,33 @@ use delegate::delegate; use itertools::Itertools; /// List of types, used for function signatures. -#[derive(Clone, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)] +/// The `ROWVARS` parameter controls whether this may contain [RowVariable]s +#[derive(Clone, Eq, Debug, serde::Serialize, serde::Deserialize)] #[non_exhaustive] #[serde(transparent)] -pub struct TypeRow { +pub struct TypeRowBase { /// The datatypes in the row. - types: Cow<'static, [Type]>, + types: Cow<'static, [TypeBase]>, } -impl Display for TypeRow { +/// Row of single types i.e. of known length, for node inputs/outputs +pub type TypeRow = TypeRowBase; + +/// Row of types and/or row variables, the number of actual types is thus unknown +pub type TypeRowRV = TypeRowBase; + +impl PartialEq> for TypeRowBase { + fn eq(&self, other: &TypeRowBase) -> bool { + self.types.len() == other.types.len() + && self + .types + .iter() + .zip(other.types.iter()) + .all(|(s, o)| s == o) + } +} + +impl Display for TypeRowBase { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_char('[')?; display_list(self.types.as_ref(), f)?; @@ -32,7 +50,7 @@ impl Display for TypeRow { } } -impl TypeRow { +impl TypeRowBase { /// Create a new empty row. pub const fn new() -> Self { Self { @@ -41,31 +59,55 @@ impl TypeRow { } /// Returns a new `TypeRow` with `xs` concatenated onto `self`. - pub fn extend<'a>(&'a self, rest: impl IntoIterator) -> Self { + pub fn extend<'a>(&'a self, rest: impl IntoIterator>) -> Self { self.iter().chain(rest).cloned().collect_vec().into() } /// Returns a reference to the types in the row. - pub fn as_slice(&self) -> &[Type] { + pub fn as_slice(&self) -> &[TypeBase] { &self.types } + /// Applies a substitution to the row. + /// For `TypeRowRV`, note this may change the length of the row. + /// For `TypeRow`, guaranteed not to change the length of the row. + pub(super) fn substitute(&self, s: &Substitution) -> Self { + self.iter() + .flat_map(|ty| ty.substitute(s)) + .collect::>() + .into() + } + delegate! { to self.types { /// Iterator over the types in the row. - pub fn iter(&self) -> impl Iterator; - - /// Returns the number of types in the row. - pub fn len(&self) -> usize; + pub fn iter(&self) -> impl Iterator>; /// Mutable vector of the types in the row. - pub fn to_mut(&mut self) -> &mut Vec; + pub fn to_mut(&mut self) -> &mut Vec>; /// Allow access (consumption) of the contained elements - pub fn into_owned(self) -> Vec; + pub fn into_owned(self) -> Vec>; /// Returns `true` if the row contains no types. pub fn is_empty(&self) -> bool ; + } + } + + pub(super) fn validate( + &self, + exts: &ExtensionRegistry, + var_decls: &[TypeParam], + ) -> Result<(), SignatureError> { + self.iter().try_for_each(|t| t.validate(exts, var_decls)) + } +} + +impl TypeRow { + delegate! { + to self.types { + /// Returns the number of types in the row. + pub fn len(&self) -> usize; #[inline(always)] /// Returns the type at the specified index. Returns `None` if out of bounds. @@ -78,47 +120,69 @@ impl TypeRow { pub fn get_mut(&mut self, offset: usize) -> Option<&mut Type>; } } +} - /// Applies a substitution to the row. Note this may change the length - /// if-and-only-if the row contains any [RowVariable]s. - /// - /// [RowVariable]: [crate::types::TypeEnum::RowVariable] - pub(super) fn substitute(&self, tr: &Substitution) -> TypeRow { - let res = self - .iter() - .flat_map(|ty| ty.substitute(tr)) - .collect::>() - .into(); - res - } - - pub(super) fn validate_var_len( - &self, - exts: &ExtensionRegistry, - var_decls: &[TypeParam], - ) -> Result<(), SignatureError> { - self.iter() - .try_for_each(|t| t.validate(true, exts, var_decls)) +impl TryFrom for TypeRow { + type Error = SignatureError; + + fn try_from(value: TypeRowRV) -> Result { + Ok(Self::from( + value + .into_owned() + .into_iter() + .map(|t| t.try_into()) + .collect::, _>>() + .map_err(|var| SignatureError::RowVarWhereTypeExpected { var })?, + )) } } -impl Default for TypeRow { +impl Default for TypeRowBase { fn default() -> Self { Self::new() } } -impl From for TypeRow -where - F: Into>, -{ - fn from(types: F) -> Self { +impl From>> for TypeRowBase { + fn from(types: Vec>) -> Self { Self { types: types.into(), } } } +impl From> for TypeRowRV { + fn from(types: Vec) -> Self { + Self { + types: types.into_iter().map(Type::into_).collect(), + } + } +} + +impl From for TypeRowRV { + fn from(value: TypeRow) -> Self { + Self { + types: value.iter().cloned().map(Type::into_).collect(), + } + } +} + +impl From<&'static [TypeBase]> for TypeRowBase { + fn from(types: &'static [TypeBase]) -> Self { + Self { + types: types.into(), + } + } +} + +impl From> for TypeRowRV { + fn from(t: TypeBase) -> Self { + Self { + types: vec![t.into_()].into(), + } + } +} + impl From for TypeRow { fn from(t: Type) -> Self { Self { @@ -127,15 +191,15 @@ impl From for TypeRow { } } -impl Deref for TypeRow { - type Target = [Type]; +impl Deref for TypeRowBase { + type Target = [TypeBase]; fn deref(&self) -> &Self::Target { self.as_slice() } } -impl DerefMut for TypeRow { +impl DerefMut for TypeRowBase { fn deref_mut(&mut self) -> &mut Self::Target { self.types.to_mut() } @@ -145,18 +209,18 @@ impl DerefMut for TypeRow { mod test { mod proptest { use crate::proptest::RecursionDepth; - use crate::{type_row, types::Type}; + use crate::types::{MaybeRV, TypeBase, TypeRowBase}; use ::proptest::prelude::*; - impl Arbitrary for super::super::TypeRow { + impl Arbitrary for super::super::TypeRowBase { type Parameters = RecursionDepth; type Strategy = BoxedStrategy; fn arbitrary_with(depth: Self::Parameters) -> Self::Strategy { use proptest::collection::vec; if depth.leaf() { - Just(type_row![]).boxed() + Just(TypeRowBase::new()).boxed() } else { - vec(any_with::(depth), 0..4) + vec(any_with::>(depth), 0..4) .prop_map(|ts| ts.to_vec().into()) .boxed() } diff --git a/hugr-core/src/utils.rs b/hugr-core/src/utils.rs index 863cfa7a9..3693743ea 100644 --- a/hugr-core/src/utils.rs +++ b/hugr-core/src/utils.rs @@ -103,6 +103,7 @@ pub(crate) fn is_default(t: &T) -> bool { #[cfg(test)] pub(crate) mod test_quantum_extension { use crate::ops::{OpName, OpNameRef}; + use crate::types::FuncValueType; use crate::{ extension::{ prelude::{BOOL_T, QB_T}, @@ -111,18 +112,18 @@ pub(crate) mod test_quantum_extension { ops::CustomOp, std_extensions::arithmetic::float_types, type_row, - types::{FunctionType, PolyFuncType}, + types::{PolyFuncTypeRV, Signature}, Extension, }; use lazy_static::lazy_static; - fn one_qb_func() -> PolyFuncType { - FunctionType::new_endo(type_row![QB_T]).into() + fn one_qb_func() -> PolyFuncTypeRV { + FuncValueType::new_endo(QB_T).into() } - fn two_qb_func() -> PolyFuncType { - FunctionType::new_endo(type_row![QB_T, QB_T]).into() + fn two_qb_func() -> PolyFuncTypeRV { + FuncValueType::new_endo(type_row![QB_T, QB_T]).into() } /// The extension identifier. pub const EXTENSION_ID: ExtensionId = ExtensionId::new_unchecked("test.quantum"); @@ -136,7 +137,7 @@ pub(crate) mod test_quantum_extension { .add_op( OpName::new_inline("RzF64"), "Rotation specified by float".into(), - FunctionType::new(type_row![QB_T, float_types::FLOAT64_TYPE], type_row![QB_T]), + Signature::new(type_row![QB_T, float_types::FLOAT64_TYPE], type_row![QB_T]), ) .unwrap(); @@ -148,7 +149,7 @@ pub(crate) mod test_quantum_extension { .add_op( OpName::new_inline("Measure"), "Measure a qubit, returning the qubit and the measurement result.".into(), - FunctionType::new(type_row![QB_T], type_row![QB_T, BOOL_T]), + Signature::new(type_row![QB_T], type_row![QB_T, BOOL_T]), ) .unwrap(); @@ -156,7 +157,7 @@ pub(crate) mod test_quantum_extension { .add_op( OpName::new_inline("QAlloc"), "Allocate a new qubit.".into(), - FunctionType::new(type_row![], type_row![QB_T]), + Signature::new(type_row![], type_row![QB_T]), ) .unwrap(); @@ -164,7 +165,7 @@ pub(crate) mod test_quantum_extension { .add_op( OpName::new_inline("QDiscard"), "Discard a qubit.".into(), - FunctionType::new(type_row![QB_T], type_row![]), + Signature::new(type_row![QB_T], type_row![]), ) .unwrap(); diff --git a/hugr-passes/src/const_fold.rs b/hugr-passes/src/const_fold.rs index c895256cd..3026e5779 100644 --- a/hugr-passes/src/const_fold.rs +++ b/hugr-passes/src/const_fold.rs @@ -2,7 +2,7 @@ use std::collections::{BTreeSet, HashMap}; -use hugr_core::builder::inout_ft; +use hugr_core::builder::inout_sig; use itertools::Itertools; use thiserror::Error; @@ -136,7 +136,7 @@ pub fn fold_leaf_op(op: &OpType, consts: &[(IncomingPort, Value)]) -> ConstFoldR /// against `reg`. fn const_graph(consts: Vec, reg: &ExtensionRegistry) -> Hugr { let const_types = consts.iter().map(Value::get_type).collect_vec(); - let mut b = DFGBuilder::new(inout_ft(type_row![], const_types)).unwrap(); + let mut b = DFGBuilder::new(inout_sig(type_row![], const_types)).unwrap(); let outputs = consts .into_iter() diff --git a/hugr-passes/src/const_fold/test.rs b/hugr-passes/src/const_fold/test.rs index 87490f485..8f3fed226 100644 --- a/hugr-passes/src/const_fold/test.rs +++ b/hugr-passes/src/const_fold/test.rs @@ -8,7 +8,7 @@ use hugr_core::std_extensions::arithmetic::int_ops::IntOpDef; use hugr_core::std_extensions::arithmetic::int_types::{ConstInt, INT_TYPES}; use hugr_core::std_extensions::logic::{self, NaryLogic, NotOp}; use hugr_core::type_row; -use hugr_core::types::{FunctionType, Type, TypeRow}; +use hugr_core::types::{Signature, Type, TypeRow, TypeRowRV}; use rstest::rstest; @@ -73,8 +73,8 @@ fn test_add(#[case] a: f64, #[case] b: f64, #[case] c: f64) { assert_eq!(outs.as_slice(), &[(0.into(), c)]); } -fn noargfn(outputs: impl Into) -> FunctionType { - inout_ft(type_row![], outputs) +fn noargfn(outputs: impl Into) -> Signature { + inout_sig(type_row![], outputs) } #[test] @@ -137,11 +137,8 @@ fn test_list_ops() -> Result<(), Box> { ]) .unwrap(); let list: Value = ListValue::new(BOOL_T, [Value::false_val()]).into(); - let mut build = DFGBuilder::new(FunctionType::new( - type_row![], - vec![list.get_type().clone()], - )) - .unwrap(); + let mut build = + DFGBuilder::new(Signature::new(type_row![], vec![list.get_type().clone()])).unwrap(); let list_wire = build.add_load_const(list.clone()); @@ -904,7 +901,7 @@ fn test_fold_idivmod_checked_u() { // x0, x1 := int_u<5>(20), int_u<3>(0) // x2 := idivmod_checked_u(x0, x1) // output x2 == error - let intpair: TypeRow = vec![INT_TYPES[5].clone(), INT_TYPES[3].clone()].into(); + let intpair: TypeRowRV = vec![INT_TYPES[5].clone(), INT_TYPES[3].clone()].into(); let sum_type = sum_with_error(Type::new_tuple(intpair)); let mut build = DFGBuilder::new(noargfn(vec![sum_type.clone().into()])).unwrap(); let x0 = build.add_load_const(Value::extension(ConstInt::new_u(5, 20).unwrap())); @@ -974,7 +971,7 @@ fn test_fold_idivmod_checked_s() { // x0, x1 := int_s<5>(-20), int_u<3>(0) // x2 := idivmod_checked_s(x0, x1) // output x2 == error - let intpair: TypeRow = vec![INT_TYPES[5].clone(), INT_TYPES[3].clone()].into(); + let intpair: TypeRowRV = vec![INT_TYPES[5].clone(), INT_TYPES[3].clone()].into(); let sum_type = sum_with_error(Type::new_tuple(intpair)); let mut build = DFGBuilder::new(noargfn(vec![sum_type.clone().into()])).unwrap(); let x0 = build.add_load_const(Value::extension(ConstInt::new_s(5, -20).unwrap())); diff --git a/hugr-passes/src/force_order.rs b/hugr-passes/src/force_order.rs index c2f7b9221..cfbec1682 100644 --- a/hugr-passes/src/force_order.rs +++ b/hugr-passes/src/force_order.rs @@ -204,14 +204,14 @@ mod test { use std::collections::HashMap; use super::*; - use hugr_core::builder::{endo_ft, BuildHandle, Dataflow, DataflowHugr}; + use hugr_core::builder::{endo_sig, BuildHandle, Dataflow, DataflowHugr}; use hugr_core::extension::EMPTY_REG; use hugr_core::ops::handle::{DataflowOpID, NodeHandle}; use hugr_core::ops::Value; use hugr_core::std_extensions::arithmetic::int_ops::{self, IntOpDef}; use hugr_core::std_extensions::arithmetic::int_types::INT_TYPES; - use hugr_core::types::{FunctionType, Type}; + use hugr_core::types::{Signature, Type}; use hugr_core::{builder::DFGBuilder, hugr::Hugr}; use hugr_core::{HugrView, Wire}; @@ -247,7 +247,7 @@ mod test { /// Output fn test_hugr() -> (Hugr, [Node; 4]) { let t = INT_TYPES[I as usize].clone(); - let mut builder = DFGBuilder::new(endo_ft(vec![t.clone(), t.clone()])).unwrap(); + let mut builder = DFGBuilder::new(endo_sig(vec![t.clone(), t.clone()])).unwrap(); let [iw1, iw2] = builder.input_wires_arr(); let v0 = build_neg(&mut builder, iw1); let v1 = build_neg(&mut builder, iw2); @@ -324,7 +324,7 @@ mod test { fn test_force_order_const() { let mut hugr = { let mut builder = - DFGBuilder::new(FunctionType::new(Type::EMPTY_TYPEROW, Type::UNIT)).unwrap(); + DFGBuilder::new(Signature::new(Type::EMPTY_TYPEROW, Type::UNIT)).unwrap(); let unit = builder.add_load_value(Value::unary_unit_sum()); builder .finish_hugr_with_outputs([unit], &EMPTY_REG) diff --git a/hugr-passes/src/merge_bbs.rs b/hugr-passes/src/merge_bbs.rs index 625eb264b..fae6b061f 100644 --- a/hugr-passes/src/merge_bbs.rs +++ b/hugr-passes/src/merge_bbs.rs @@ -161,14 +161,14 @@ mod test { use itertools::Itertools; use rstest::rstest; - use hugr_core::builder::{endo_ft, inout_ft, CFGBuilder, DFGWrapper, Dataflow, HugrBuilder}; + use hugr_core::builder::{endo_sig, inout_sig, CFGBuilder, DFGWrapper, Dataflow, HugrBuilder}; use hugr_core::extension::prelude::{ConstUsize, PRELUDE_ID, QB_T, USIZE_T}; use hugr_core::extension::{ExtensionRegistry, PRELUDE, PRELUDE_REGISTRY}; use hugr_core::hugr::views::sibling::SiblingMut; use hugr_core::ops::constant::Value; use hugr_core::ops::handle::CfgID; use hugr_core::ops::{Lift, LoadConstant, Noop, OpTrait, OpType}; - use hugr_core::types::{FunctionType, Type, TypeRow}; + use hugr_core::types::{Signature, Type, TypeRow}; use hugr_core::{const_extension_ids, type_row, Extension, Hugr, HugrView, Wire}; use super::merge_basic_blocks; @@ -182,7 +182,7 @@ mod test { e.add_op( "Test".into(), String::new(), - FunctionType::new( + Signature::new( type_row![QB_T, USIZE_T], TypeRow::from(vec![Type::new_sum(vec![ type_row![QB_T], @@ -197,7 +197,10 @@ mod test { fn lifted_unary_unit_sum + AsRef, T>(b: &mut DFGWrapper) -> Wire { let lc = b.add_load_value(Value::unary_unit_sum()); let lift = b - .add_dataflow_op(Lift::new(Type::new_unit_sum(1).into(), PRELUDE_ID), [lc]) + .add_dataflow_op( + Lift::new(type_row![Type::new_unit_sum(1)], PRELUDE_ID), + [lc], + ) .unwrap(); let [w] = lift.outputs_arr(); w @@ -223,7 +226,7 @@ mod test { let e = extension(); let tst_op = e.instantiate_extension_op("Test", [], &PRELUDE_REGISTRY)?; let reg = ExtensionRegistry::try_new([PRELUDE.to_owned(), e])?; - let mut h = CFGBuilder::new(inout_ft(loop_variants.clone(), exit_types.clone()))?; + let mut h = CFGBuilder::new(inout_sig(loop_variants.clone(), exit_types.clone()))?; let mut no_b1 = h.simple_entry_builder_exts(loop_variants.clone(), 1, PRELUDE_ID)?; let n = no_b1.add_dataflow_op(Noop::new(QB_T), no_b1.input_wires())?; let br = lifted_unary_unit_sum(&mut no_b1); @@ -242,7 +245,7 @@ mod test { let loop_backedge_target = if self_loop { no_b1 } else { - let mut no_b2 = h.simple_block_builder(endo_ft(loop_variants), 1)?; + let mut no_b2 = h.simple_block_builder(endo_sig(loop_variants), 1)?; let n = no_b2.add_dataflow_op(Noop::new(QB_T), no_b2.input_wires())?; let br = lifted_unary_unit_sum(&mut no_b2); let nid = no_b2.finish_with_outputs(br, n.outputs())?; @@ -318,7 +321,7 @@ mod test { .into_owned() .try_into() .unwrap(); - let mut h = CFGBuilder::new(inout_ft(QB_T, res_t.clone()))?; + let mut h = CFGBuilder::new(inout_sig(QB_T, res_t.clone()))?; let mut bb1 = h.simple_entry_builder(type_row![USIZE_T, QB_T], 1)?; let [inw] = bb1.input_wires_arr(); let load_cst = bb1.add_load_value(ConstUsize::new(1)); diff --git a/hugr-passes/src/nest_cfgs.rs b/hugr-passes/src/nest_cfgs.rs index 08b857b1f..617950f9e 100644 --- a/hugr-passes/src/nest_cfgs.rs +++ b/hugr-passes/src/nest_cfgs.rs @@ -575,7 +575,7 @@ impl EdgeClassifier { pub(crate) mod test { use super::*; use hugr_core::builder::{ - endo_ft, BuildError, CFGBuilder, Container, DataflowSubContainer, HugrBuilder, + endo_sig, BuildError, CFGBuilder, Container, DataflowSubContainer, HugrBuilder, }; use hugr_core::extension::PRELUDE_REGISTRY; use hugr_core::extension::{prelude::USIZE_T, ExtensionSet}; @@ -585,7 +585,7 @@ pub(crate) mod test { use hugr_core::ops::handle::{ConstID, NodeHandle}; use hugr_core::ops::Value; use hugr_core::type_row; - use hugr_core::types::{EdgeKind, FunctionType, Type}; + use hugr_core::types::{EdgeKind, Signature, Type}; use hugr_core::utils::depth; const NAT: Type = USIZE_T; @@ -608,7 +608,7 @@ pub(crate) mod test { // /-> left --\ // entry -> split > merge -> head -> tail -> exit // \-> right -/ \-<--<-/ - let mut cfg_builder = CFGBuilder::new(FunctionType::new_endo(NAT))?; + let mut cfg_builder = CFGBuilder::new(Signature::new_endo(NAT))?; let pred_const = cfg_builder.add_constant(Value::unit_sum(0, 2).expect("0 < 2")); let const_unit = cfg_builder.add_constant(Value::unary_unit_sum()); @@ -620,11 +620,11 @@ pub(crate) mod test { let (split, merge) = build_if_then_else_merge(&mut cfg_builder, &pred_const, &const_unit)?; cfg_builder.branch(&entry, 0, &split)?; let head = n_identity( - cfg_builder.simple_block_builder(endo_ft(NAT), 1)?, + cfg_builder.simple_block_builder(endo_sig(NAT), 1)?, &const_unit, )?; let tail = n_identity( - cfg_builder.simple_block_builder(endo_ft(NAT), 2)?, + cfg_builder.simple_block_builder(endo_sig(NAT), 2)?, &pred_const, )?; cfg_builder.branch(&tail, 1, &head)?; @@ -851,7 +851,7 @@ pub(crate) mod test { const_pred: &ConstID, unit_const: &ConstID, ) -> Result<(BasicBlockID, BasicBlockID), BuildError> { - let split = n_identity(cfg.simple_block_builder(endo_ft(NAT), 2)?, const_pred)?; + let split = n_identity(cfg.simple_block_builder(endo_sig(NAT), 2)?, const_pred)?; let merge = build_then_else_merge_from_if(cfg, unit_const, split)?; Ok((split, merge)) } @@ -861,9 +861,9 @@ pub(crate) mod test { unit_const: &ConstID, split: BasicBlockID, ) -> Result { - let merge = n_identity(cfg.simple_block_builder(endo_ft(NAT), 1)?, unit_const)?; - let left = n_identity(cfg.simple_block_builder(endo_ft(NAT), 1)?, unit_const)?; - let right = n_identity(cfg.simple_block_builder(endo_ft(NAT), 1)?, unit_const)?; + let merge = n_identity(cfg.simple_block_builder(endo_sig(NAT), 1)?, unit_const)?; + let left = n_identity(cfg.simple_block_builder(endo_sig(NAT), 1)?, unit_const)?; + let right = n_identity(cfg.simple_block_builder(endo_sig(NAT), 1)?, unit_const)?; cfg.branch(&split, 0, &left)?; cfg.branch(&split, 1, &right)?; cfg.branch(&left, 0, &merge)?; @@ -876,7 +876,7 @@ pub(crate) mod test { // \-> right -/ \-<--<-/ // Result is Hugr plus merge and tail blocks fn build_cond_then_loop_cfg() -> Result<(Hugr, BasicBlockID, BasicBlockID), BuildError> { - let mut cfg_builder = CFGBuilder::new(FunctionType::new_endo(NAT))?; + let mut cfg_builder = CFGBuilder::new(Signature::new_endo(NAT))?; let pred_const = cfg_builder.add_constant(Value::unit_sum(0, 2).expect("0 < 2")); let const_unit = cfg_builder.add_constant(Value::unary_unit_sum()); @@ -887,7 +887,7 @@ pub(crate) mod test { let merge = build_then_else_merge_from_if(&mut cfg_builder, &const_unit, entry)?; // The merge block is also the loop header (so it merges three incoming control-flow edges) let tail = n_identity( - cfg_builder.simple_block_builder(endo_ft(NAT), 2)?, + cfg_builder.simple_block_builder(endo_sig(NAT), 2)?, &pred_const, )?; cfg_builder.branch(&tail, 1, &merge)?; @@ -903,7 +903,7 @@ pub(crate) mod test { pub(crate) fn build_conditional_in_loop_cfg( separate_headers: bool, ) -> Result<(Hugr, BasicBlockID, BasicBlockID), BuildError> { - let mut cfg_builder = CFGBuilder::new(FunctionType::new_endo(NAT))?; + let mut cfg_builder = CFGBuilder::new(Signature::new_endo(NAT))?; let (head, tail) = build_conditional_in_loop(&mut cfg_builder, separate_headers)?; let h = cfg_builder.finish_prelude_hugr()?; Ok((h, head, tail)) @@ -924,7 +924,7 @@ pub(crate) mod test { let head = if separate_headers { let head = n_identity( - cfg_builder.simple_block_builder(endo_ft(NAT), 1)?, + cfg_builder.simple_block_builder(endo_sig(NAT), 1)?, &const_unit, )?; cfg_builder.branch(&head, 0, &split)?; @@ -934,7 +934,7 @@ pub(crate) mod test { split }; let tail = n_identity( - cfg_builder.simple_block_builder(endo_ft(NAT), 2)?, + cfg_builder.simple_block_builder(endo_sig(NAT), 2)?, &pred_const, )?; cfg_builder.branch(&tail, 1, &head)?; diff --git a/hugr/benches/benchmarks/hugr.rs b/hugr/benches/benchmarks/hugr.rs index eb7fe60de..ee28742c3 100644 --- a/hugr/benches/benchmarks/hugr.rs +++ b/hugr/benches/benchmarks/hugr.rs @@ -3,12 +3,12 @@ use criterion::{black_box, criterion_group, AxisScale, Criterion, PlotConfiguration}; use hugr::builder::{BuildError, CFGBuilder, DFGBuilder, Dataflow, DataflowHugr, HugrBuilder}; use hugr::extension::prelude::{BOOL_T, USIZE_T}; -use hugr::types::FunctionType; +use hugr::types::Signature; use hugr::{type_row, Hugr}; pub fn simple_dfg_hugr() -> Hugr { let dfg_builder = - DFGBuilder::new(FunctionType::new(type_row![BOOL_T], type_row![BOOL_T])).unwrap(); + DFGBuilder::new(Signature::new(type_row![BOOL_T], type_row![BOOL_T])).unwrap(); let [i1] = dfg_builder.input_wires_arr(); dfg_builder.finish_prelude_hugr_with_outputs([i1]).unwrap() } @@ -25,7 +25,7 @@ pub fn simple_cfg_builder + AsRef>( entry_b.finish_with_outputs(sum, [])? }; let mut middle_b = cfg_builder - .simple_block_builder(FunctionType::new(type_row![USIZE_T], type_row![USIZE_T]), 1)?; + .simple_block_builder(Signature::new(type_row![USIZE_T], type_row![USIZE_T]), 1)?; let middle = { let c = middle_b.add_load_const(hugr::ops::Value::unary_unit_sum()); let [inw] = middle_b.input_wires_arr(); @@ -40,7 +40,7 @@ pub fn simple_cfg_builder + AsRef>( pub fn simple_cfg_hugr() -> Hugr { let mut cfg_builder = - CFGBuilder::new(FunctionType::new(type_row![USIZE_T], type_row![USIZE_T])).unwrap(); + CFGBuilder::new(Signature::new(type_row![USIZE_T], type_row![USIZE_T])).unwrap(); simple_cfg_builder(&mut cfg_builder).unwrap(); cfg_builder.finish_prelude_hugr().unwrap() } diff --git a/hugr/benches/benchmarks/types.rs b/hugr/benches/benchmarks/types.rs index 3b599983c..a109a05d8 100644 --- a/hugr/benches/benchmarks/types.rs +++ b/hugr/benches/benchmarks/types.rs @@ -2,7 +2,7 @@ #![allow(clippy::unit_arg)] use hugr::extension::prelude::{QB_T, USIZE_T}; use hugr::ops::AliasDecl; -use hugr::types::{FunctionType, Type, TypeBound}; +use hugr::types::{Signature, Type, TypeBound}; use criterion::{black_box, criterion_group, AxisScale, Criterion, PlotConfiguration}; @@ -13,8 +13,8 @@ fn make_complex_type() -> Type { let q_register = Type::new_tuple(vec![qb; 8]); let b_register = Type::new_tuple(vec![int; 8]); let q_alias = Type::new_alias(AliasDecl::new("QReg", TypeBound::Any)); - let sum = Type::new_sum([vec![q_register].into(), vec![q_alias].into()]); - Type::new_function(FunctionType::new(vec![sum], vec![b_register])) + let sum = Type::new_sum([q_register, q_alias]); + Type::new_function(Signature::new(vec![sum], vec![b_register])) } fn bench_construction(c: &mut Criterion) { diff --git a/hugr/src/lib.rs b/hugr/src/lib.rs index e4db4258c..f142cffc8 100644 --- a/hugr/src/lib.rs +++ b/hugr/src/lib.rs @@ -27,11 +27,11 @@ //! To build a HUGR for a simple quantum circuit and then serialize it to a buffer, we can define //! a simple quantum extension and then use the [[builder::DFGBuilder]] as follows: //! ``` -//! use hugr::builder::{BuildError, DFGBuilder, Dataflow, DataflowHugr, inout_ft}; +//! use hugr::builder::{BuildError, DFGBuilder, Dataflow, DataflowHugr, inout_sig}; //! use hugr::extension::prelude::{BOOL_T, QB_T}; //! use hugr::hugr::Hugr; //! use hugr::type_row; -//! use hugr::types::FunctionType; +//! use hugr::types::FuncValueType; //! //! // The type of qubits, `QB_T` is in the prelude but, by default, no gateset //! // is defined. This module provides Hadamard and CX gates. @@ -43,18 +43,18 @@ //! }, //! ops::{CustomOp, OpName}, //! type_row, -//! types::{FunctionType, PolyFuncType}, +//! types::{FuncValueType, PolyFuncTypeRV}, //! Extension, //! }; //! //! use lazy_static::lazy_static; //! -//! fn one_qb_func() -> PolyFuncType { -//! FunctionType::new_endo(type_row![QB_T]).into() +//! fn one_qb_func() -> PolyFuncTypeRV { +//! FuncValueType::new_endo(type_row![QB_T]).into() //! } //! -//! fn two_qb_func() -> PolyFuncType { -//! FunctionType::new_endo(type_row![QB_T, QB_T]).into() +//! fn two_qb_func() -> PolyFuncTypeRV { +//! FuncValueType::new_endo(type_row![QB_T, QB_T]).into() //! } //! /// The extension identifier. //! pub const EXTENSION_ID: ExtensionId = ExtensionId::new_unchecked("mini.quantum"); @@ -73,7 +73,7 @@ //! .add_op( //! OpName::new_inline("Measure"), //! "Measure a qubit, returning the qubit and the measurement result.".into(), -//! FunctionType::new(type_row![QB_T], type_row![QB_T, BOOL_T]), +//! FuncValueType::new(type_row![QB_T], type_row![QB_T, BOOL_T]), //! ) //! .unwrap(); //! @@ -115,7 +115,7 @@ //! // └───┘└───┘└╥┘ //! // c: ╚═ //! fn make_dfg_hugr() -> Result { -//! let mut dfg_builder = DFGBuilder::new(inout_ft( +//! let mut dfg_builder = DFGBuilder::new(inout_sig( //! type_row![QB_T, QB_T], //! type_row![QB_T, QB_T, BOOL_T], //! ))?;