From ee60c728467d735357be2a4eabd96d92136938b7 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 7 Jul 2023 13:26:29 +0100 Subject: [PATCH 01/47] In ConstValue::predicate, assert that the unit value is expected by the type --- src/ops/constant.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ops/constant.rs b/src/ops/constant.rs index 0715f610b..341a066f7 100644 --- a/src/ops/constant.rs +++ b/src/ops/constant.rs @@ -174,9 +174,11 @@ impl ConstValue { /// Constant Sum over Tuples, used as predicates. pub fn predicate(tag: usize, variant_rows: impl IntoIterator) -> Self { + let variants = TypeRow::predicate_variants_row(variant_rows); + assert!(variants.get(tag) == Some(&SimpleType::new_unit())); ConstValue::Sum { tag, - variants: TypeRow::predicate_variants_row(variant_rows), + variants, val: Box::new(Self::unit()), } } From 900ffce5a5ff94361cfb14d488beffa1c7757a1c Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 7 Jul 2023 13:43:48 +0100 Subject: [PATCH 02/47] Remove one TypeRow::from, inlining into the other --- src/types/simple.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/types/simple.rs b/src/types/simple.rs index 04b0f29ed..7f15f4905 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -371,17 +371,6 @@ impl TypeRow { } } - /// Create a new row from a Cow slice of types. - /// - /// See [`type_row!`] for a more ergonomic way to create a statically allocated rows. - /// - /// [`type_row!`]: crate::macros::type_row. - pub fn from(types: impl Into>) -> Self { - Self { - types: types.into(), - } - } - /// Iterator over the types in the row. pub fn iter(&self) -> impl Iterator { self.types.iter() @@ -427,7 +416,9 @@ where T: Into>, { fn from(types: T) -> Self { - Self::from(types.into()) + Self { + types: types.into(), + } } } From 5455cd9803cf19ec01937c40777a8f54028a2b00 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 7 Jul 2023 15:02:03 +0100 Subject: [PATCH 03/47] Linear containers can have classic values too --- src/ops/handle.rs | 4 ++-- src/types/simple.rs | 27 ++++++++++++++------------- src/types/simple/serialize.rs | 18 ++++++++---------- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/ops/handle.rs b/src/ops/handle.rs index f033aec21..e4804d929 100644 --- a/src/ops/handle.rs +++ b/src/ops/handle.rs @@ -1,6 +1,6 @@ //! Handles to nodes in HUGR. //! -use crate::types::{ClassicType, Container, LinearType, SimpleType}; +use crate::types::{ClassicType, Container, SimpleType}; use crate::Node; use derive_more::From as DerFrom; @@ -86,7 +86,7 @@ impl AliasID { /// Construct new AliasID pub fn get_alias_type(&self) -> SimpleType { if self.linear { - Container::::Alias(self.name.clone()).into() + Container::::Alias(self.name.clone()).into() } else { Container::::Alias(self.name.clone()).into() } diff --git a/src/types/simple.rs b/src/types/simple.rs index 7f15f4905..f3eb81bab 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -15,7 +15,7 @@ use super::{custom::CustomType, Signature}; use crate::{ops::constant::HugrIntWidthStore, utils::display_list}; use crate::{resource::ResourceSet, type_row}; -/// A type that represents concrete data. +/// A type that represents concrete data. Can include both linear and classical parts. /// // TODO: Derive pyclass // @@ -24,7 +24,7 @@ use crate::{resource::ResourceSet, type_row}; #[serde(from = "serialize::SerSimpleType", into = "serialize::SerSimpleType")] #[non_exhaustive] pub enum SimpleType { - /// A type containing classical data. Elements of this type can be copied. + /// A type containing only classical data. Elements of this type can be copied. Classic(ClassicType), /// A type containing linear data. Elements of this type must be used exactly once. Linear(LinearType), @@ -41,13 +41,13 @@ impl Display for SimpleType { } } -/// Trait of primitive types (ClassicType or LinearType). +/// Trait of primitive types (SimpleType or ClassicType). pub trait PrimType { // may be updated with functions in future for necessary shared functionality - // across ClassicType and LinearType + // across ClassicType and SimpleType // currently used to constrain Container - /// Is this type linear + /// Is this type linear? (I.e. does it have any linear components?) const LINEAR: bool; } @@ -91,9 +91,9 @@ impl From> for SimpleType { } } -impl From> for SimpleType { +impl From> for SimpleType { #[inline] - fn from(value: Container) -> Self { + fn from(value: Container) -> Self { Self::Linear(LinearType::Container(value)) } } @@ -194,7 +194,8 @@ impl PrimType for ClassicType { const LINEAR: bool = false; } -/// A type that represents concrete linear data. +/// A subselection of [SimpleType] that may contain linear data, i.e. distinct +/// from [ClassicType] which definitely does not. /// // TODO: Derive pyclass. #[derive(Clone, Debug, Default, PartialEq, Eq)] @@ -206,7 +207,7 @@ pub enum LinearType { /// A linear opaque operation that can be downcasted by the extensions that define it. Qpaque(CustomType), /// A nested definition containing other linear types. - Container(Container), + Container(Container), } impl Display for LinearType { @@ -219,12 +220,12 @@ impl Display for LinearType { } } -impl PrimType for LinearType { +impl PrimType for SimpleType { const LINEAR: bool = true; } impl SimpleType { - /// Returns whether the type contains only linear data. + /// Returns whether the type contains linear data (perhaps as well as classical) pub fn is_linear(&self) -> bool { matches!(self, Self::Linear(_)) } @@ -240,7 +241,7 @@ impl SimpleType { if row.purely_classical() { Container::::Sum(Box::new(row)).into() } else { - Container::::Sum(Box::new(row)).into() + Container::::Sum(Box::new(row)).into() } } @@ -250,7 +251,7 @@ impl SimpleType { if row.purely_classical() { Container::::Tuple(Box::new(row)).into() } else { - Container::::Tuple(Box::new(row)).into() + Container::::Tuple(Box::new(row)).into() } } diff --git a/src/types/simple/serialize.rs b/src/types/simple/serialize.rs index 394687491..21c5a2fd6 100644 --- a/src/types/simple/serialize.rs +++ b/src/types/simple/serialize.rs @@ -167,7 +167,7 @@ impl From for SimpleType { SerSimpleType::Tuple { row: inner, l: true, - } => Container::::Tuple(box_convert_try(*inner)).into(), + } => Container::::Tuple(box_convert_try(*inner)).into(), SerSimpleType::Tuple { row: inner, l: false, @@ -175,22 +175,20 @@ impl From for SimpleType { SerSimpleType::Sum { row: inner, l: true, - } => Container::::Sum(box_convert_try(*inner)).into(), + } => Container::::Sum(box_convert_try(*inner)).into(), SerSimpleType::Sum { row: inner, l: false, } => Container::::Sum(box_convert_try(*inner)).into(), SerSimpleType::List { inner, l: true } => { - Container::::List(box_convert_try(*inner)).into() + Container::::List(box_convert_try(*inner)).into() } SerSimpleType::List { inner, l: false } => { Container::::List(box_convert_try(*inner)).into() } - SerSimpleType::Map { k, v, l: true } => Container::::Map(Box::new(( - (*k).try_into().unwrap(), - (*v).try_into().unwrap(), - ))) - .into(), + SerSimpleType::Map { k, v, l: true } => { + Container::::Map(Box::new(((*k).try_into().unwrap(), *v))).into() + } SerSimpleType::Map { k, v, l: false } => Container::::Map(Box::new(( (*k).try_into().unwrap(), (*v).try_into().unwrap(), @@ -200,13 +198,13 @@ impl From for SimpleType { inner, len, l: true, - } => Container::::Array(box_convert_try(*inner), len).into(), + } => Container::::Array(box_convert_try(*inner), len).into(), SerSimpleType::Array { inner, len, l: false, } => Container::::Array(box_convert_try(*inner), len).into(), - SerSimpleType::Alias { name: s, l: true } => Container::::Alias(s).into(), + SerSimpleType::Alias { name: s, l: true } => Container::::Alias(s).into(), SerSimpleType::Alias { name: s, l: false } => Container::::Alias(s).into(), SerSimpleType::Opaque { custom: c, l: true } => LinearType::Qpaque(c).into(), SerSimpleType::Opaque { From de40c363ac7764489e32a2b68fc4b8bcfd2e3096 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 7 Jul 2023 15:21:36 +0100 Subject: [PATCH 04/47] Flatten LinearType into SimpleType --- src/builder.rs | 9 +++--- src/builder/build_traits.rs | 15 +++++---- src/builder/dataflow.rs | 5 +-- src/hugr/region.rs | 4 +-- src/hugr/rewrite/simple_replace.rs | 6 ++-- src/hugr/serialize.rs | 6 ++-- src/hugr/validate.rs | 4 +-- src/ops/leaf.rs | 8 ++--- src/types.rs | 2 +- src/types/simple.rs | 49 +++++++----------------------- src/types/simple/serialize.rs | 25 +++++---------- 11 files changed, 49 insertions(+), 84 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 4388dc27c..68b8e3a50 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -4,8 +4,7 @@ use thiserror::Error; use crate::hugr::{HugrError, Node, ValidationError, Wire}; use crate::ops::handle::{BasicBlockID, CfgID, ConditionalID, DfgID, FuncID, TailLoopID}; - -use crate::types::LinearType; +use crate::types::SimpleType; pub mod handle; pub use handle::BuildHandle; @@ -63,7 +62,7 @@ pub enum BuildError { /// Can't copy a linear type #[error("Can't copy linear type: {0:?}.")] - NoCopyLinear(LinearType), + NoCopyLinear(SimpleType), /// Error in CircuitBuilder #[error("Error in CircuitBuilder: {0}.")] @@ -72,7 +71,7 @@ pub enum BuildError { #[cfg(test)] mod test { - use crate::types::{ClassicType, LinearType, Signature, SimpleType}; + use crate::types::{ClassicType, Signature, SimpleType}; use crate::Hugr; use super::handle::BuildHandle; @@ -82,7 +81,7 @@ mod test { pub(super) const NAT: SimpleType = SimpleType::Classic(ClassicType::i64()); pub(super) const F64: SimpleType = SimpleType::Classic(ClassicType::F64); pub(super) const BIT: SimpleType = SimpleType::Classic(ClassicType::bit()); - pub(super) const QB: SimpleType = SimpleType::Linear(LinearType::Qubit); + pub(super) const QB: SimpleType = SimpleType::Qubit; /// Wire up inputs of a Dataflow container to the outputs. pub(super) fn n_identity( diff --git a/src/builder/build_traits.rs b/src/builder/build_traits.rs index 6216edf87..cfc8c1516 100644 --- a/src/builder/build_traits.rs +++ b/src/builder/build_traits.rs @@ -16,7 +16,7 @@ use crate::{ types::EdgeKind, }; -use crate::types::{LinearType, Signature, SimpleType, TypeRow}; +use crate::types::{Signature, SimpleType, TypeRow}; use itertools::Itertools; @@ -660,7 +660,7 @@ fn wire_up( #[derive(Debug, Clone, PartialEq, Eq)] enum ValueKind { Classic, - Linear(LinearType), + Linear(SimpleType), Const, } @@ -671,10 +671,13 @@ fn get_value_kind(base: &Hugr, src: Node, src_offset: Port) -> ValueKind { let wire_kind = base.get_optype(src).port_kind(src_offset).unwrap(); match wire_kind { EdgeKind::Static(_) => ValueKind::Const, - EdgeKind::Value(simple_type) => match simple_type { - SimpleType::Classic(_) => ValueKind::Classic, - SimpleType::Linear(typ) => ValueKind::Linear(typ), - }, + EdgeKind::Value(simple_type) => { + if simple_type.is_linear() { + ValueKind::Linear(simple_type) + } else { + ValueKind::Classic + } + } _ => { panic!("Wires can only be Const or Value kind") } diff --git a/src/builder/dataflow.rs b/src/builder/dataflow.rs index d5a9ef128..d250b7763 100644 --- a/src/builder/dataflow.rs +++ b/src/builder/dataflow.rs @@ -195,6 +195,7 @@ mod test { use crate::builder::{DataflowSubContainer, ModuleBuilder}; use crate::ops::tag::OpTag; use crate::ops::OpTrait; + use crate::types::SimpleType; use crate::{ builder::{ test::{n_identity, BIT, NAT, QB}, @@ -203,7 +204,7 @@ mod test { ops::LeafOp, resource::ResourceSet, type_row, - types::{LinearType, Signature}, + types::Signature, Wire, }; @@ -304,7 +305,7 @@ mod test { Ok(module_builder.finish_hugr()?) }; - assert_eq!(builder(), Err(BuildError::NoCopyLinear(LinearType::Qubit))); + assert_eq!(builder(), Err(BuildError::NoCopyLinear(SimpleType::Qubit))); } #[test] diff --git a/src/hugr/region.rs b/src/hugr/region.rs index 6ad62f21c..8c0bc4bde 100644 --- a/src/hugr/region.rs +++ b/src/hugr/region.rs @@ -332,13 +332,13 @@ mod test { builder::{Container, Dataflow, DataflowSubContainer, HugrBuilder, ModuleBuilder}, ops::{handle::NodeHandle, LeafOp}, type_row, - types::{ClassicType, LinearType, Signature, SimpleType}, + types::{ClassicType, Signature, SimpleType}, }; use super::*; const NAT: SimpleType = SimpleType::Classic(ClassicType::i64()); - const QB: SimpleType = SimpleType::Linear(LinearType::Qubit); + const QB: SimpleType = SimpleType::Qubit; /// Make a module hugr with a fn definition containing an inner dfg node. /// diff --git a/src/hugr/rewrite/simple_replace.rs b/src/hugr/rewrite/simple_replace.rs index fd36ddeb0..4b6bd2b33 100644 --- a/src/hugr/rewrite/simple_replace.rs +++ b/src/hugr/rewrite/simple_replace.rs @@ -266,12 +266,12 @@ mod test { use crate::hugr::{Hugr, Node}; use crate::ops::tag::OpTag; use crate::ops::{LeafOp, OpTrait, OpType}; - use crate::types::{ClassicType, LinearType, Signature, SimpleType}; + use crate::types::{ClassicType, Signature, SimpleType}; use crate::{type_row, Port}; use super::SimpleReplacement; - const QB: SimpleType = SimpleType::Linear(LinearType::Qubit); + const QB: SimpleType = SimpleType::Qubit; /// Creates a hugr like the following: /// -- H -- @@ -511,7 +511,7 @@ mod test { #[test] fn test_replace_cx_cross() { - let q_row: Vec = vec![LinearType::Qubit.into(), LinearType::Qubit.into()]; + let q_row: Vec = vec![SimpleType::Qubit, SimpleType::Qubit]; let mut builder = DFGBuilder::new(q_row.clone(), q_row).unwrap(); let mut circ = builder.as_circuit(builder.input_wires().collect()); circ.append(LeafOp::CX, [0, 1]).unwrap(); diff --git a/src/hugr/serialize.rs b/src/hugr/serialize.rs index f086f1a36..e23bf4b8e 100644 --- a/src/hugr/serialize.rs +++ b/src/hugr/serialize.rs @@ -246,7 +246,7 @@ pub mod test { ModuleBuilder, }, ops::{dataflow::IOTrait, Input, LeafOp, Module, Output, DFG}, - types::{ClassicType, LinearType, Signature, SimpleType}, + types::{ClassicType, Signature, SimpleType}, Port, }; use itertools::Itertools; @@ -255,7 +255,7 @@ pub mod test { }; const NAT: SimpleType = SimpleType::Classic(ClassicType::i64()); - const QB: SimpleType = SimpleType::Linear(LinearType::Qubit); + const QB: SimpleType = SimpleType::Qubit; #[test] fn empty_hugr_serialize() { @@ -425,7 +425,7 @@ pub mod test { #[test] fn hierarchy_order() { - let qb: SimpleType = LinearType::Qubit.into(); + let qb = SimpleType::Qubit; let dfg = DFGBuilder::new([qb.clone()].to_vec(), [qb.clone()].to_vec()).unwrap(); let [old_in, out] = dfg.io(); let w = dfg.input_wires(); diff --git a/src/hugr/validate.rs b/src/hugr/validate.rs index 54c5d54b7..fd0e6cc5f 100644 --- a/src/hugr/validate.rs +++ b/src/hugr/validate.rs @@ -740,13 +740,13 @@ mod test { use crate::hugr::{HugrError, HugrMut}; use crate::ops::dataflow::IOTrait; use crate::ops::{self, ConstValue, LeafOp, OpType}; - use crate::types::{ClassicType, LinearType, Signature}; + use crate::types::{ClassicType, Signature}; use crate::Direction; use crate::{type_row, Node}; const NAT: SimpleType = SimpleType::Classic(ClassicType::i64()); const B: SimpleType = SimpleType::Classic(ClassicType::bit()); - const Q: SimpleType = SimpleType::Linear(LinearType::Qubit); + const Q: SimpleType = SimpleType::Qubit; /// Creates a hugr with a single function definition that copies a bit `copies` times. /// diff --git a/src/ops/leaf.rs b/src/ops/leaf.rs index 05e0d2a7c..aaab90094 100644 --- a/src/ops/leaf.rs +++ b/src/ops/leaf.rs @@ -7,9 +7,7 @@ use super::{tag::OpTag, OpName, OpTrait}; use crate::{ resource::{ResourceId, ResourceSet}, type_row, - types::{ - ClassicType, EdgeKind, LinearType, Signature, SignatureDescription, SimpleType, TypeRow, - }, + types::{ClassicType, EdgeKind, Signature, SignatureDescription, SimpleType, TypeRow}, }; /// Dataflow operations with no children. @@ -85,7 +83,7 @@ pub enum LeafOp { impl Default for LeafOp { fn default() -> Self { Self::Noop { - ty: SimpleType::default(), + ty: SimpleType::Qubit, } } } @@ -153,7 +151,7 @@ impl OpTrait for LeafOp { fn signature(&self) -> Signature { // Static signatures. The `TypeRow`s in the `Signature` use a // copy-on-write strategy, so we can avoid unnecessary allocations. - const Q: SimpleType = SimpleType::Linear(LinearType::Qubit); + const Q: SimpleType = SimpleType::Qubit; const B: SimpleType = SimpleType::Classic(ClassicType::bit()); const F: SimpleType = SimpleType::Classic(ClassicType::F64); diff --git a/src/types.rs b/src/types.rs index d755b1f8b..8a37bb6dc 100644 --- a/src/types.rs +++ b/src/types.rs @@ -11,7 +11,7 @@ use std::ops::Index; use pyo3::prelude::*; pub use custom::CustomType; -pub use simple::{ClassicType, Container, LinearType, SimpleType, TypeRow}; +pub use simple::{ClassicType, Container, SimpleType, TypeRow}; use smol_str::SmolStr; diff --git a/src/types/simple.rs b/src/types/simple.rs index f3eb81bab..6f287b50a 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -26,8 +26,12 @@ use crate::{resource::ResourceSet, type_row}; pub enum SimpleType { /// A type containing only classical data. Elements of this type can be copied. Classic(ClassicType), - /// A type containing linear data. Elements of this type must be used exactly once. - Linear(LinearType), + /// A qubit. + Qubit, + /// A linear opaque type that can be downcasted by the extensions that define it. + Qpaque(CustomType), + /// A nested definition containing other linear types (possibly as well as classical ones) + Qontainer(Container), } mod serialize; @@ -36,7 +40,9 @@ impl Display for SimpleType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { SimpleType::Classic(ty) => ty.fmt(f), - SimpleType::Linear(ty) => ty.fmt(f), + SimpleType::Qubit => f.write_str("Qubit"), + SimpleType::Qpaque(custom) => custom.fmt(f), + SimpleType::Qontainer(c) => c.fmt(f), } } } @@ -94,7 +100,7 @@ impl From> for SimpleType { impl From> for SimpleType { #[inline] fn from(value: Container) -> Self { - Self::Linear(LinearType::Container(value)) + Self::Qontainer(value) } } @@ -194,32 +200,6 @@ impl PrimType for ClassicType { const LINEAR: bool = false; } -/// A subselection of [SimpleType] that may contain linear data, i.e. distinct -/// from [ClassicType] which definitely does not. -/// -// TODO: Derive pyclass. -#[derive(Clone, Debug, Default, PartialEq, Eq)] -#[non_exhaustive] -pub enum LinearType { - /// A qubit. - #[default] - Qubit, - /// A linear opaque operation that can be downcasted by the extensions that define it. - Qpaque(CustomType), - /// A nested definition containing other linear types. - Container(Container), -} - -impl Display for LinearType { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - LinearType::Qubit => f.write_str("Qubit"), - LinearType::Qpaque(custom) => custom.fmt(f), - LinearType::Container(c) => c.fmt(f), - } - } -} - impl PrimType for SimpleType { const LINEAR: bool = true; } @@ -227,7 +207,7 @@ impl PrimType for SimpleType { impl SimpleType { /// Returns whether the type contains linear data (perhaps as well as classical) pub fn is_linear(&self) -> bool { - matches!(self, Self::Linear(_)) + !self.is_classical() } /// Returns whether the type contains only classic data. @@ -274,12 +254,6 @@ impl SimpleType { } } -impl Default for SimpleType { - fn default() -> Self { - Self::Linear(Default::default()) - } -} - /// Implementations of Into and TryFrom for SimpleType and &'a SimpleType. macro_rules! impl_from_into_simple_type { ($target:ident, $matcher:pat, $unpack:expr, $new:expr) => { @@ -318,7 +292,6 @@ impl_from_into_simple_type!( typ, SimpleType::Classic ); -impl_from_into_simple_type!(LinearType, SimpleType::Linear(typ), typ, SimpleType::Linear); /// List of types, used for function signatures. #[derive(Clone, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)] diff --git a/src/types/simple/serialize.rs b/src/types/simple/serialize.rs index 21c5a2fd6..2bb978593 100644 --- a/src/types/simple/serialize.rs +++ b/src/types/simple/serialize.rs @@ -2,7 +2,6 @@ use super::ClassicType; use super::Container; -use super::LinearType; use super::PrimType; use smol_str::SmolStr; @@ -116,24 +115,16 @@ impl From for SerSimpleType { } } -impl From for SerSimpleType { - fn from(value: LinearType) -> Self { - match value { - LinearType::Qubit => SerSimpleType::Q, - LinearType::Container(c) => c.into(), - LinearType::Qpaque(inner) => SerSimpleType::Opaque { - custom: inner, - l: true, - }, - } - } -} - impl From for SerSimpleType { fn from(value: SimpleType) -> Self { match value { - SimpleType::Linear(l) => l.into(), SimpleType::Classic(c) => c.into(), + SimpleType::Qubit => SerSimpleType::Q, + SimpleType::Qontainer(c) => c.into(), + SimpleType::Qpaque(inner) => SerSimpleType::Opaque { + custom: inner, + l: true, + }, } } } @@ -156,7 +147,7 @@ where impl From for SimpleType { fn from(value: SerSimpleType) -> Self { match value { - SerSimpleType::Q => LinearType::Qubit.into(), + SerSimpleType::Q => SimpleType::Qubit, SerSimpleType::I { width } => ClassicType::Int(width).into(), SerSimpleType::F => ClassicType::F64.into(), SerSimpleType::S => ClassicType::String.into(), @@ -206,7 +197,7 @@ impl From for SimpleType { } => Container::::Array(box_convert_try(*inner), len).into(), SerSimpleType::Alias { name: s, l: true } => Container::::Alias(s).into(), SerSimpleType::Alias { name: s, l: false } => Container::::Alias(s).into(), - SerSimpleType::Opaque { custom: c, l: true } => LinearType::Qpaque(c).into(), + SerSimpleType::Opaque { custom: c, l: true } => SimpleType::Qpaque(c), SerSimpleType::Opaque { custom: c, l: false, From 4d585f8f6141a80f5cbb09beed8b3790b3aa346e Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 7 Jul 2023 15:26:36 +0100 Subject: [PATCH 05/47] Inline single use of impl_from_into_simple_type macro --- src/types/simple.rs | 51 ++++++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/src/types/simple.rs b/src/types/simple.rs index 6f287b50a..32aa44954 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -254,44 +254,33 @@ impl SimpleType { } } -/// Implementations of Into and TryFrom for SimpleType and &'a SimpleType. -macro_rules! impl_from_into_simple_type { - ($target:ident, $matcher:pat, $unpack:expr, $new:expr) => { - impl From<$target> for SimpleType { - fn from(typ: $target) -> Self { - $new(typ) - } - } +impl From for SimpleType { + fn from(typ: ClassicType) -> Self { + SimpleType::Classic(typ) + } +} - impl TryFrom for $target { - type Error = &'static str; +impl TryFrom for ClassicType { + type Error = &'static str; - fn try_from(op: SimpleType) -> Result { - match op { - $matcher => Ok($unpack), - _ => Err("Invalid type conversion"), - } - } + fn try_from(op: SimpleType) -> Result { + match op { + SimpleType::Classic(typ) => Ok(typ), + _ => Err("Invalid type conversion"), } + } +} - impl<'a> TryFrom<&'a SimpleType> for &'a $target { - type Error = &'static str; +impl<'a> TryFrom<&'a SimpleType> for &'a ClassicType { + type Error = &'static str; - fn try_from(op: &'a SimpleType) -> Result { - match op { - $matcher => Ok($unpack), - _ => Err("Invalid type conversion"), - } - } + fn try_from(op: &'a SimpleType) -> Result { + match op { + SimpleType::Classic(typ) => Ok(typ), + _ => Err("Invalid type conversion"), } - }; + } } -impl_from_into_simple_type!( - ClassicType, - SimpleType::Classic(typ), - typ, - SimpleType::Classic -); /// List of types, used for function signatures. #[derive(Clone, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)] From 6ccc5fa0887669b12cea0a4d72617209066870f3 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 7 Jul 2023 17:13:59 +0100 Subject: [PATCH 06/47] WIP --- src/builder/build_traits.rs | 12 +++--- src/builder/cfg.rs | 42 ++++++++++----------- src/builder/conditional.rs | 10 ++--- src/builder/dataflow.rs | 6 +-- src/builder/tail_loop.rs | 10 ++--- src/extensions/rotation.rs | 2 +- src/hugr/typecheck.rs | 2 +- src/macros.rs | 4 +- src/ops/constant.rs | 8 ++-- src/ops/controlflow.rs | 38 +++++++++---------- src/ops/dataflow.rs | 10 ++--- src/ops/leaf.rs | 8 ++-- src/ops/validate.rs | 10 ++--- src/resource.rs | 4 +- src/types.rs | 22 +++++------ src/types/simple.rs | 71 ++++++++++++++++++----------------- src/types/simple/serialize.rs | 4 +- 17 files changed, 134 insertions(+), 129 deletions(-) diff --git a/src/builder/build_traits.rs b/src/builder/build_traits.rs index cfc8c1516..273bb69f4 100644 --- a/src/builder/build_traits.rs +++ b/src/builder/build_traits.rs @@ -277,7 +277,7 @@ pub trait Dataflow: Container { fn cfg_builder( &mut self, inputs: impl IntoIterator, - output_types: TypeRow, + output_types: TypeRow, ) -> Result, BuildError> { let (input_types, input_wires): (Vec, Vec) = inputs.into_iter().unzip(); @@ -336,7 +336,7 @@ pub trait Dataflow: Container { &mut self, just_inputs: impl IntoIterator, inputs_outputs: impl IntoIterator, - just_out_types: TypeRow, + just_out_types: TypeRow, ) -> Result, BuildError> { let (input_types, mut input_wires): (Vec, Vec) = just_inputs.into_iter().unzip(); @@ -368,9 +368,9 @@ pub trait Dataflow: Container { /// the Conditional node. fn conditional_builder( &mut self, - (predicate_inputs, predicate_wire): (impl IntoIterator, Wire), + (predicate_inputs, predicate_wire): (impl IntoIterator>, Wire), other_inputs: impl IntoIterator, - output_types: TypeRow, + output_types: TypeRow, ) -> Result, BuildError> { let mut input_wires = vec![predicate_wire]; let (input_types, rest_input_wires): (Vec, Vec) = @@ -452,7 +452,7 @@ pub trait Dataflow: Container { fn make_tag( &mut self, tag: usize, - variants: impl Into, + variants: impl Into>, value: Wire, ) -> Result { let make_op = self.add_dataflow_op( @@ -470,7 +470,7 @@ pub trait Dataflow: Container { fn make_predicate( &mut self, tag: usize, - predicate_variants: impl IntoIterator, + predicate_variants: impl IntoIterator>, values: impl IntoIterator, ) -> Result { let tuple = self.make_tuple(values)?; diff --git a/src/builder/cfg.rs b/src/builder/cfg.rs index 5d7188d57..c1a96d0d5 100644 --- a/src/builder/cfg.rs +++ b/src/builder/cfg.rs @@ -22,7 +22,7 @@ use crate::{hugr::HugrMut, types::TypeRow, Hugr}; pub struct CFGBuilder { pub(super) base: T, pub(super) cfg_node: Node, - pub(super) inputs: Option, + pub(super) inputs: Option>, pub(super) exit_node: Node, pub(super) n_out_wires: usize, } @@ -54,7 +54,7 @@ impl + AsRef> SubContainer for CFGBuilder { impl CFGBuilder { /// New CFG rooted HUGR builder - pub fn new(input: impl Into, output: impl Into) -> Result { + pub fn new(input: impl Into>, output: impl Into>) -> Result { let input = input.into(); let output = output.into(); let cfg_op = ops::CFG { @@ -79,8 +79,8 @@ impl + AsRef> CFGBuilder { pub(super) fn create( mut base: B, cfg_node: Node, - input: TypeRow, - output: TypeRow, + input: TypeRow, + output: TypeRow, ) -> Result { let n_out_wires = output.len(); let exit_block_type = OpType::BasicBlock(BasicBlock::Exit { @@ -122,18 +122,18 @@ impl + AsRef> CFGBuilder { /// This function will return an error if there is an error adding the node. pub fn block_builder( &mut self, - inputs: TypeRow, - predicate_variants: Vec, - other_outputs: TypeRow, + inputs: TypeRow, + predicate_variants: Vec>, + other_outputs: TypeRow, ) -> Result, BuildError> { self.any_block_builder(inputs, predicate_variants, other_outputs, false) } fn any_block_builder( &mut self, - inputs: TypeRow, - predicate_variants: Vec, - other_outputs: TypeRow, + inputs: TypeRow, + predicate_variants: Vec>, + other_outputs: TypeRow, entry: bool, ) -> Result, BuildError> { let op = OpType::BasicBlock(BasicBlock::DFB { @@ -166,8 +166,8 @@ impl + AsRef> CFGBuilder { /// This function will return an error if there is an error adding the node. pub fn simple_block_builder( &mut self, - inputs: TypeRow, - outputs: TypeRow, + inputs: TypeRow, + outputs: TypeRow, n_cases: usize, ) -> Result, BuildError> { self.block_builder(inputs, vec![type_row![]; n_cases], outputs) @@ -182,8 +182,8 @@ impl + AsRef> CFGBuilder { /// This function will return an error if an entry block has already been built. pub fn entry_builder( &mut self, - predicate_variants: Vec, - other_outputs: TypeRow, + predicate_variants: Vec>, + other_outputs: TypeRow, ) -> Result, BuildError> { let inputs = self .inputs @@ -200,7 +200,7 @@ impl + AsRef> CFGBuilder { /// This function will return an error if there is an error adding the node. pub fn simple_entry_builder( &mut self, - outputs: TypeRow, + outputs: TypeRow, n_cases: usize, ) -> Result, BuildError> { self.entry_builder(vec![type_row![]; n_cases], outputs) @@ -244,9 +244,9 @@ impl + AsRef> BlockBuilder { fn create( base: B, block_n: Node, - predicate_variants: Vec, - other_outputs: TypeRow, - inputs: TypeRow, + predicate_variants: Vec>, + other_outputs: TypeRow, + inputs: TypeRow, ) -> Result { // The node outputs a predicate before the data outputs of the block node let predicate_type = SimpleType::new_predicate(predicate_variants); @@ -275,9 +275,9 @@ impl + AsRef> BlockBuilder { impl BlockBuilder { /// Initialize a [`BasicBlock::DFB`] rooted HUGR builder pub fn new( - inputs: impl Into, - predicate_variants: impl IntoIterator, - other_outputs: impl Into, + inputs: impl Into>, + predicate_variants: impl IntoIterator>, + other_outputs: impl Into>, ) -> Result { let inputs = inputs.into(); let predicate_variants: Vec<_> = predicate_variants.into_iter().collect(); diff --git a/src/builder/conditional.rs b/src/builder/conditional.rs index 38c7d7b16..c6975f8e6 100644 --- a/src/builder/conditional.rs +++ b/src/builder/conditional.rs @@ -1,5 +1,5 @@ use crate::hugr::view::HugrView; -use crate::types::{Signature, TypeRow}; +use crate::types::{Signature, TypeRow, SimpleType}; use crate::ops; use crate::ops::handle::CaseID; @@ -146,9 +146,9 @@ impl HugrBuilder for ConditionalBuilder { impl ConditionalBuilder { /// Initialize a Conditional rooted HUGR builder pub fn new( - predicate_inputs: impl IntoIterator, - other_inputs: impl Into, - outputs: impl Into, + predicate_inputs: impl IntoIterator>, + other_inputs: impl Into>, + outputs: impl Into>, ) -> Result { let predicate_inputs: Vec<_> = predicate_inputs.into_iter().collect(); let other_inputs = other_inputs.into(); @@ -176,7 +176,7 @@ impl ConditionalBuilder { impl CaseBuilder { /// Initialize a Case rooted HUGR - pub fn new(input: impl Into, output: impl Into) -> Result { + pub fn new(input: impl Into>, output: impl Into>) -> Result { let input = input.into(); let output = output.into(); let signature = Signature::new_df(input, output); diff --git a/src/builder/dataflow.rs b/src/builder/dataflow.rs index d250b7763..cb1aeb7ed 100644 --- a/src/builder/dataflow.rs +++ b/src/builder/dataflow.rs @@ -7,7 +7,7 @@ use std::marker::PhantomData; use crate::hugr::{HugrView, ValidationError}; use crate::ops; -use crate::types::{Signature, TypeRow}; +use crate::types::{Signature, TypeRow, SimpleType}; use crate::Node; use crate::{hugr::HugrMut, Hugr}; @@ -60,8 +60,8 @@ impl DFGBuilder { /// /// Error in adding DFG child nodes. pub fn new( - input: impl Into, - output: impl Into, + input: impl Into>, + output: impl Into>, ) -> Result, BuildError> { let input = input.into(); let output = output.into(); diff --git a/src/builder/tail_loop.rs b/src/builder/tail_loop.rs index c109b158e..6e6022f33 100644 --- a/src/builder/tail_loop.rs +++ b/src/builder/tail_loop.rs @@ -1,7 +1,7 @@ use crate::ops::{self, OpType}; use crate::hugr::view::HugrView; -use crate::types::{Signature, TypeRow}; +use crate::types::{Signature, TypeRow, SimpleType}; use crate::{Hugr, Node}; use super::build_traits::SubContainer; @@ -49,7 +49,7 @@ impl + AsRef> TailLoopBuilder { } /// The output types of the child graph, including the predicate as the first. - pub fn internal_output_row(&self) -> Result { + pub fn internal_output_row(&self) -> Result, BuildError> { self.loop_signature().map(ops::TailLoop::body_output_row) } } @@ -72,9 +72,9 @@ impl + AsRef> TailLoopBuilder { impl TailLoopBuilder { /// Initialize new builder for a [`ops::TailLoop`] rooted HUGR pub fn new( - just_inputs: impl Into, - inputs_outputs: impl Into, - just_outputs: impl Into, + just_inputs: impl Into>, + inputs_outputs: impl Into>, + just_outputs: impl Into>, ) -> Result { let tail_loop = ops::TailLoop { just_inputs: just_inputs.into(), diff --git a/src/extensions/rotation.rs b/src/extensions/rotation.rs index c49f15153..d8f36f82f 100644 --- a/src/extensions/rotation.rs +++ b/src/extensions/rotation.rs @@ -109,7 +109,7 @@ impl CustomSignatureFunc for AngleAdd { _name: &SmolStr, _arg_values: &[TypeArg], _misc: &HashMap, - ) -> Result<(TypeRow, TypeRow, ResourceSet), SignatureError> { + ) -> Result<(TypeRow, TypeRow, ResourceSet), SignatureError> { let t: TypeRow = vec![SimpleType::Classic( Into::::into(Type::Angle).into(), )] diff --git a/src/hugr/typecheck.rs b/src/hugr/typecheck.rs index a7189bcae..af288e255 100644 --- a/src/hugr/typecheck.rs +++ b/src/hugr/typecheck.rs @@ -56,7 +56,7 @@ pub enum ConstTypeError { /// A mismatch between the embedded type and the type we're checking /// against, as above, but for rows instead of simple types #[error("Type mismatch for const - expected {0}, found {1}")] - TypeRowMismatch(TypeRow, TypeRow), + TypeRowMismatch(TypeRow, TypeRow), } lazy_static! { diff --git a/src/macros.rs b/src/macros.rs index d9bcb1204..f33028794 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -64,7 +64,7 @@ macro_rules! type_row { { use $crate::types; static ROW: &[types::SimpleType] = &[$($t),*]; - let row: types::TypeRow = ROW.into(); + let row: types::TypeRow<_> = ROW.into(); row } }; @@ -72,7 +72,7 @@ macro_rules! type_row { { use $crate::types; static ROW: &[types::SimpleType] = &[$t; $n]; - let row: types::TypeRow = ROW.into(); + let row: types::TypeRow<_> = ROW.into(); row } }; diff --git a/src/ops/constant.rs b/src/ops/constant.rs index 341a066f7..6881299a7 100644 --- a/src/ops/constant.rs +++ b/src/ops/constant.rs @@ -59,7 +59,9 @@ pub enum ConstValue { /// A constant specifying a variant of a Sum type. Sum { tag: usize, - variants: TypeRow, + // The *type* could have linear types in other variants, so long as + // the value was of another variant + variants: TypeRow, val: Box, }, /// A tuple of constant values. @@ -173,7 +175,7 @@ impl ConstValue { } /// Constant Sum over Tuples, used as predicates. - pub fn predicate(tag: usize, variant_rows: impl IntoIterator) -> Self { + pub fn predicate(tag: usize, variant_rows: impl IntoIterator>) -> Self { let variants = TypeRow::predicate_variants_row(variant_rows); assert!(variants.get(tag) == Some(&SimpleType::new_unit())); ConstValue::Sum { @@ -184,7 +186,7 @@ impl ConstValue { } /// Constant Sum over Tuples with just one variant - pub fn unary_predicate(row: impl Into) -> Self { + pub fn unary_predicate(row: impl Into>) -> Self { Self::predicate(0, [row.into()]) } diff --git a/src/ops/controlflow.rs b/src/ops/controlflow.rs index 823375e02..412aacb39 100644 --- a/src/ops/controlflow.rs +++ b/src/ops/controlflow.rs @@ -12,11 +12,11 @@ use super::{impl_op_name, OpName, OpTrait}; #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct TailLoop { /// Types that are only input - pub just_inputs: TypeRow, + pub just_inputs: TypeRow, /// Types that are only output - pub just_outputs: TypeRow, + pub just_outputs: TypeRow, /// Types that are appended to both input and output - pub rest: TypeRow, + pub rest: TypeRow, } impl_op_name!(TailLoop); @@ -42,7 +42,7 @@ impl DataflowOpTrait for TailLoop { impl TailLoop { /// Build the output TypeRow of the child graph of a TailLoop node. - pub(crate) fn body_output_row(&self) -> TypeRow { + pub(crate) fn body_output_row(&self) -> TypeRow { let predicate = SimpleType::new_predicate([self.just_inputs.clone(), self.just_outputs.clone()]); let mut outputs = vec![predicate]; @@ -51,7 +51,7 @@ impl TailLoop { } /// Build the input TypeRow of the child graph of a TailLoop node. - pub(crate) fn body_input_row(&self) -> TypeRow { + pub(crate) fn body_input_row(&self) -> TypeRow { let mut inputs = self.just_inputs.clone(); inputs.to_mut().extend_from_slice(&self.rest); inputs @@ -62,11 +62,11 @@ impl TailLoop { #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct Conditional { /// The possible rows of the predicate input - pub predicate_inputs: Vec, + pub predicate_inputs: Vec>, /// Remaining input types - pub other_inputs: TypeRow, + pub other_inputs: TypeRow, /// Output types - pub outputs: TypeRow, + pub outputs: TypeRow, } impl_op_name!(Conditional); @@ -91,7 +91,7 @@ impl DataflowOpTrait for Conditional { impl Conditional { /// Build the input TypeRow of the nth child graph of a Conditional node. - pub(crate) fn case_input_row(&self, case: usize) -> Option { + pub(crate) fn case_input_row(&self, case: usize) -> Option> { let mut inputs = self.predicate_inputs.get(case)?.clone(); inputs.to_mut().extend_from_slice(&self.other_inputs); @@ -103,8 +103,8 @@ impl Conditional { #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] #[allow(missing_docs)] pub struct CFG { - pub inputs: TypeRow, - pub outputs: TypeRow, + pub inputs: TypeRow, + pub outputs: TypeRow, } impl_op_name!(CFG); @@ -130,13 +130,13 @@ impl DataflowOpTrait for CFG { pub enum BasicBlock { /// A CFG basic block node. The signature is that of the internal Dataflow graph. DFB { - inputs: TypeRow, - other_outputs: TypeRow, - predicate_variants: Vec, + inputs: TypeRow, + other_outputs: TypeRow, + predicate_variants: Vec>, }, /// The single exit node of the CFG, has no children, /// stores the types of the CFG node output. - Exit { cfg_outputs: TypeRow }, + Exit { cfg_outputs: TypeRow }, } impl OpName for BasicBlock { @@ -176,7 +176,7 @@ impl OpTrait for BasicBlock { impl BasicBlock { /// The input signature of the contained dataflow graph. - pub fn dataflow_input(&self) -> &TypeRow { + pub fn dataflow_input(&self) -> &TypeRow { match self { BasicBlock::DFB { inputs, .. } => inputs, BasicBlock::Exit { cfg_outputs } => cfg_outputs, @@ -185,7 +185,7 @@ impl BasicBlock { /// The correct inputs of any successors. Returns None if successor is not a /// valid index. - pub fn successor_input(&self, successor: usize) -> Option { + pub fn successor_input(&self, successor: usize) -> Option> { match self { BasicBlock::DFB { predicate_variants, @@ -222,12 +222,12 @@ impl OpTrait for Case { impl Case { /// The input signature of the contained dataflow graph. - pub fn dataflow_input(&self) -> &TypeRow { + pub fn dataflow_input(&self) -> &TypeRow { &self.signature.input } /// The output signature of the contained dataflow graph. - pub fn dataflow_output(&self) -> &TypeRow { + pub fn dataflow_output(&self) -> &TypeRow { &self.signature.output } } diff --git a/src/ops/dataflow.rs b/src/ops/dataflow.rs index 6bf15b78a..0908e0e15 100644 --- a/src/ops/dataflow.rs +++ b/src/ops/dataflow.rs @@ -30,7 +30,7 @@ pub(super) trait DataflowOpTrait { /// Helpers to construct input and output nodes pub trait IOTrait { /// Construct a new I/O node from a type row with no resource requirements - fn new(types: impl Into) -> Self; + fn new(types: impl Into>) -> Self; /// Helper method to add resource requirements to an I/O node fn with_resources(self, rs: ResourceSet) -> Self; } @@ -40,7 +40,7 @@ pub trait IOTrait { #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct Input { /// Input value types - pub types: TypeRow, + pub types: TypeRow, /// Resources attached to output wires pub resources: ResourceSet, } @@ -48,7 +48,7 @@ pub struct Input { impl_op_name!(Input); impl IOTrait for Input { - fn new(types: impl Into) -> Self { + fn new(types: impl Into>) -> Self { Input { types: types.into(), resources: ResourceSet::new(), @@ -65,7 +65,7 @@ impl IOTrait for Input { #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct Output { /// Output value types - pub types: TypeRow, + pub types: TypeRow, /// Resources expected from input wires pub resources: ResourceSet, } @@ -73,7 +73,7 @@ pub struct Output { impl_op_name!(Output); impl IOTrait for Output { - fn new(types: impl Into) -> Self { + fn new(types: impl Into>) -> Self { Output { types: types.into(), resources: ResourceSet::new(), diff --git a/src/ops/leaf.rs b/src/ops/leaf.rs index aaab90094..7e91df415 100644 --- a/src/ops/leaf.rs +++ b/src/ops/leaf.rs @@ -54,25 +54,25 @@ pub enum LeafOp { /// An operation that packs all its inputs into a tuple. MakeTuple { ///Tuple element types. - tys: TypeRow, + tys: TypeRow, }, /// An operation that unpacks a tuple into its components. UnpackTuple { ///Tuple element types. - tys: TypeRow, + tys: TypeRow, }, /// An operation that creates a tagged sum value from one of its variants. Tag { /// The variant to create. tag: usize, /// The variants of the sum type. - variants: TypeRow, + variants: TypeRow, }, /// A node which adds a resource req to the types of the wires it is passed /// It has no effect on the values passed along the edge Lift { /// The types of the edges - type_row: TypeRow, + type_row: TypeRow, /// The resources which are present in both the inputs and outputs input_resources: ResourceSet, /// The resources which we're adding to the inputs diff --git a/src/ops/validate.rs b/src/ops/validate.rs index 19b9c18a5..7fdde519b 100644 --- a/src/ops/validate.rs +++ b/src/ops/validate.rs @@ -241,8 +241,8 @@ pub enum ChildrenValidationError { #[error("The {node_desc} node of a {container_desc} has a signature of {actual:?}, which differs from the expected type row {expected:?}")] IOSignatureMismatch { child: NodeIndex, - actual: TypeRow, - expected: TypeRow, + actual: TypeRow, + expected: TypeRow, node_desc: &'static str, container_desc: &'static str, }, @@ -255,7 +255,7 @@ pub enum ChildrenValidationError { child: NodeIndex, expected_count: usize, actual_count: usize, - actual_predicate_rows: Vec, + actual_predicate_rows: Vec>, }, } @@ -382,8 +382,8 @@ impl ValidateOp for super::Case { /// nodes outside of the first and second elements respectively, and that those /// have the correct signature. fn validate_io_nodes<'a>( - expected_input: &TypeRow, - expected_output: &TypeRow, + expected_input: &TypeRow, + expected_output: &TypeRow, container_desc: &'static str, mut children: impl Iterator, ) -> Result<(), ChildrenValidationError> { diff --git a/src/resource.rs b/src/resource.rs index deb279c95..73b50a1f0 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -12,7 +12,7 @@ use smol_str::SmolStr; use thiserror::Error; use crate::types::type_param::{check_type_arg, TypeArgError}; -use crate::types::TypeRow; +use crate::types::{TypeRow, SimpleType}; use crate::types::{ type_param::{TypeArg, TypeParam}, Signature, SignatureDescription, @@ -29,7 +29,7 @@ pub trait CustomSignatureFunc: Send + Sync { name: &SmolStr, arg_values: &[TypeArg], misc: &HashMap, - ) -> Result<(TypeRow, TypeRow, ResourceSet), SignatureError>; + ) -> Result<(TypeRow, TypeRow, ResourceSet), SignatureError>; /// Describe the signature of a node, given the operation name, /// values for the type parameters, diff --git a/src/types.rs b/src/types.rs index 8a37bb6dc..c4ed5f90f 100644 --- a/src/types.rs +++ b/src/types.rs @@ -50,11 +50,11 @@ impl EdgeKind { #[derive(Clone, Default, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct Signature { /// Value inputs of the function. - pub input: TypeRow, + pub input: TypeRow, /// Value outputs of the function. - pub output: TypeRow, + pub output: TypeRow, /// Possible static input (for call / load-constant). - pub static_input: TypeRow, + pub static_input: TypeRow, /// The resource requirements of all the inputs pub input_resources: ResourceSet, /// The resource requirements of all the outputs @@ -233,9 +233,9 @@ impl Signature { impl Signature { /// Create a new signature. pub fn new( - input: impl Into, - output: impl Into, - static_input: impl Into, + input: impl Into>, + output: impl Into>, + static_input: impl Into>, ) -> Self { Self { input: input.into(), @@ -247,13 +247,13 @@ impl Signature { } /// Create a new signature with the same input and output types. - pub fn new_linear(linear: impl Into) -> Self { + pub fn new_linear(linear: impl Into>) -> Self { let linear = linear.into(); Signature::new_df(linear.clone(), linear) } /// Create a new signature with only dataflow inputs and outputs. - pub fn new_df(input: impl Into, output: impl Into) -> Self { + pub fn new_df(input: impl Into>, output: impl Into>) -> Self { Signature::new(input, output, type_row![]) } } @@ -326,10 +326,10 @@ impl SignatureDescription { } } - fn row_zip<'a>( - type_row: &'a TypeRow, + fn row_zip<'a, T>( + type_row: &'a TypeRow, name_row: &'a [SmolStr], - ) -> impl Iterator { + ) -> impl Iterator { name_row .iter() .chain(&EmptyStringIterator) diff --git a/src/types/simple.rs b/src/types/simple.rs index 32aa44954..06fee2da4 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -68,9 +68,9 @@ pub enum Container { /// Hash map from hashable key type to value T. Map(Box<(ClassicType, T)>), /// Product type, known-size tuple over elements of type row. - Tuple(Box), + Tuple(Box>), /// Product type, variants are tagged by their position in the type row. - Sum(Box), + Sum(Box>), /// Known size array of T. Array(Box, usize), /// Alias defined in AliasDefn or AliasDecl nodes. @@ -157,7 +157,7 @@ impl ClassicType { /// New Sum of Tuple types, used as predicates in branching. /// Tuple rows are defined in order by input rows. - pub fn new_predicate(variant_rows: impl IntoIterator) -> Self { + pub fn new_predicate(variant_rows: impl IntoIterator>) -> Self { Self::Container(Container::Sum(Box::new(TypeRow::predicate_variants_row( variant_rows, )))) @@ -216,7 +216,7 @@ impl SimpleType { } /// New Sum type, variants defined by TypeRow. - pub fn new_sum(row: impl Into) -> Self { + pub fn new_sum(row: impl Into>) -> Self { let row = row.into(); if row.purely_classical() { Container::::Sum(Box::new(row)).into() @@ -226,7 +226,7 @@ impl SimpleType { } /// New Tuple type, elements defined by TypeRow. - pub fn new_tuple(row: impl Into) -> Self { + pub fn new_tuple(row: impl Into>) -> Self { let row = row.into(); if row.purely_classical() { Container::::Tuple(Box::new(row)).into() @@ -244,7 +244,7 @@ impl SimpleType { /// New Sum of Tuple types, used as predicates in branching. /// Tuple rows are defined in order by input rows. - pub fn new_predicate(variant_rows: impl IntoIterator) -> Self { + pub fn new_predicate(variant_rows: impl IntoIterator>) -> Self { Self::Classic(ClassicType::new_predicate(variant_rows)) } @@ -287,12 +287,12 @@ impl<'a> TryFrom<&'a SimpleType> for &'a ClassicType { #[cfg_attr(feature = "pyo3", pyclass)] #[non_exhaustive] #[serde(transparent)] -pub struct TypeRow { +pub struct TypeRow { /// The datatypes in the row. - types: Cow<'static, [SimpleType]>, + types: Cow<'static, [T]>, } -impl Display for TypeRow { +impl Display for TypeRow { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_char('[')?; display_list(self.types.as_ref(), f)?; @@ -301,7 +301,7 @@ impl Display for TypeRow { } #[cfg_attr(feature = "pyo3", pymethods)] -impl TypeRow { +impl TypeRow { /// Returns the number of types in the row. #[inline(always)] pub fn len(&self) -> usize { @@ -313,7 +313,9 @@ impl TypeRow { pub fn is_empty(&self) -> bool { self.types.len() == 0 } +} +impl TypeRow { /// Returns whether the row contains only linear data. #[inline(always)] pub fn purely_linear(&self) -> bool { @@ -325,8 +327,20 @@ impl TypeRow { pub fn purely_classical(&self) -> bool { self.types.iter().all(SimpleType::is_classical) } + + #[inline] + /// Return the type row of variants required to define a Sum of Tuples type + /// given the rows of each tuple + pub fn predicate_variants_row(variant_rows: impl IntoIterator>) -> Self { + variant_rows + .into_iter() + .map(|row| SimpleType::Classic(ClassicType::Container(Container::Tuple(Box::new(row))))) + .collect_vec() + .into() + } } -impl TypeRow { + +impl TypeRow { /// Create a new empty row. pub const fn new() -> Self { Self { @@ -335,65 +349,54 @@ impl TypeRow { } /// Iterator over the types in the row. - pub fn iter(&self) -> impl Iterator { + pub fn iter(&self) -> impl Iterator { self.types.iter() } /// Mutable iterator over the types in the row. - pub fn to_mut(&mut self) -> &mut Vec { + pub fn to_mut(&mut self) -> &mut Vec { self.types.to_mut() } #[inline(always)] /// Returns the port type given an offset. Returns `None` if the offset is out of bounds. - pub fn get(&self, offset: usize) -> Option<&SimpleType> { + pub fn get(&self, offset: usize) -> Option<&T> { self.types.get(offset) } #[inline(always)] /// Returns the port type given an offset. Returns `None` if the offset is out of bounds. - pub fn get_mut(&mut self, offset: usize) -> Option<&mut SimpleType> { + pub fn get_mut(&mut self, offset: usize) -> Option<&mut T> { self.types.to_mut().get_mut(offset) } - - #[inline] - /// Return the type row of variants required to define a Sum of Tuples type - /// given the rows of each tuple - pub fn predicate_variants_row(variant_rows: impl IntoIterator) -> Self { - variant_rows - .into_iter() - .map(|row| SimpleType::Classic(ClassicType::Container(Container::Tuple(Box::new(row))))) - .collect_vec() - .into() - } } -impl Default for TypeRow { +impl Default for TypeRow { fn default() -> Self { Self::new() } } -impl From for TypeRow +impl From for TypeRow where - T: Into>, + F: Into>, { - fn from(types: T) -> Self { + fn from(types: F) -> Self { Self { - types: types.into(), + types: types.into() } } } -impl Deref for TypeRow { - type Target = [SimpleType]; +impl Deref for TypeRow { + type Target = [T]; fn deref(&self) -> &Self::Target { &self.types } } -impl DerefMut for TypeRow { +impl DerefMut for TypeRow { fn deref_mut(&mut self) -> &mut Self::Target { self.types.to_mut() } diff --git a/src/types/simple/serialize.rs b/src/types/simple/serialize.rs index 2bb978593..2cffd53ce 100644 --- a/src/types/simple/serialize.rs +++ b/src/types/simple/serialize.rs @@ -40,11 +40,11 @@ pub(crate) enum SerSimpleType { l: bool, }, Tuple { - row: Box, + row: Box>, l: bool, }, Sum { - row: Box, + row: Box>, l: bool, }, Array { From 68772ba69645f8eb8cf30cccd1bde103b1e52d6b Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 7 Jul 2023 15:53:06 +0100 Subject: [PATCH 07/47] Masses of ToOwned/'static weirdness --- src/types.rs | 2 +- src/types/simple.rs | 24 +++++++++++++----------- src/types/simple/serialize.rs | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/types.rs b/src/types.rs index c4ed5f90f..298ff8584 100644 --- a/src/types.rs +++ b/src/types.rs @@ -329,7 +329,7 @@ impl SignatureDescription { fn row_zip<'a, T>( type_row: &'a TypeRow, name_row: &'a [SmolStr], - ) -> impl Iterator { + ) -> impl Iterator where [T]: ToOwned { name_row .iter() .chain(&EmptyStringIterator) diff --git a/src/types/simple.rs b/src/types/simple.rs index 06fee2da4..8bdf2e271 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -48,7 +48,7 @@ impl Display for SimpleType { } /// Trait of primitive types (SimpleType or ClassicType). -pub trait PrimType { +pub trait PrimType: 'static { // may be updated with functions in future for necessary shared functionality // across ClassicType and SimpleType // currently used to constrain Container @@ -62,7 +62,7 @@ pub trait PrimType { /// For algebraic types Sum, Tuple if one element of type row is linear, the /// overall type is too. #[derive(Clone, Debug, PartialEq, Eq)] -pub enum Container { +pub enum Container where [T]: ToOwned { /// Variable sized list of T. List(Box), /// Hash map from hashable key type to value T. @@ -77,7 +77,7 @@ pub enum Container { Alias(SmolStr), } -impl Display for Container { +impl Display for Container where [T]: ToOwned { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { Container::List(ty) => write!(f, "List({})", ty.as_ref()), @@ -287,12 +287,12 @@ impl<'a> TryFrom<&'a SimpleType> for &'a ClassicType { #[cfg_attr(feature = "pyo3", pyclass)] #[non_exhaustive] #[serde(transparent)] -pub struct TypeRow { +pub struct TypeRow where [T]: ToOwned + 'static { /// The datatypes in the row. types: Cow<'static, [T]>, } -impl Display for TypeRow { +impl Display for TypeRow where [T]: ToOwned { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_char('[')?; display_list(self.types.as_ref(), f)?; @@ -301,7 +301,7 @@ impl Display for TypeRow { } #[cfg_attr(feature = "pyo3", pymethods)] -impl TypeRow { +impl TypeRow where [T]: ToOwned { /// Returns the number of types in the row. #[inline(always)] pub fn len(&self) -> usize { @@ -340,7 +340,7 @@ impl TypeRow { } } -impl TypeRow { +impl TypeRow where [T]: ToOwned> { /// Create a new empty row. pub const fn new() -> Self { Self { @@ -371,15 +371,17 @@ impl TypeRow { } } -impl Default for TypeRow { +impl Default for TypeRow +where [T]: ToOwned { fn default() -> Self { Self::new() } } -impl From for TypeRow +impl From for TypeRow where F: Into>, + [T]: ToOwned { fn from(types: F) -> Self { Self { @@ -388,7 +390,7 @@ where } } -impl Deref for TypeRow { +impl Deref for TypeRow where [T]: ToOwned { type Target = [T]; fn deref(&self) -> &Self::Target { @@ -396,7 +398,7 @@ impl Deref for TypeRow { } } -impl DerefMut for TypeRow { +impl DerefMut for TypeRow where [T]: ToOwned { fn deref_mut(&mut self) -> &mut Self::Target { self.types.to_mut() } diff --git a/src/types/simple/serialize.rs b/src/types/simple/serialize.rs index 2cffd53ce..b4fea4490 100644 --- a/src/types/simple/serialize.rs +++ b/src/types/simple/serialize.rs @@ -65,7 +65,7 @@ pub(crate) enum SerSimpleType { }, } -impl> From> for SerSimpleType { +impl> From> for SerSimpleType where [T]: ToOwned { fn from(value: Container) -> Self { match value { Container::Sum(inner) => SerSimpleType::Sum { From 757426f53775e2cb102aa81e83ef6b10813ef0f5 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 7 Jul 2023 16:13:55 +0100 Subject: [PATCH 08/47] Require Debug everywhere --- src/types.rs | 2 +- src/types/simple.rs | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/types.rs b/src/types.rs index 298ff8584..19a0102a1 100644 --- a/src/types.rs +++ b/src/types.rs @@ -326,7 +326,7 @@ impl SignatureDescription { } } - fn row_zip<'a, T>( + fn row_zip<'a, T: std::fmt::Debug>( type_row: &'a TypeRow, name_row: &'a [SmolStr], ) -> impl Iterator where [T]: ToOwned { diff --git a/src/types/simple.rs b/src/types/simple.rs index 8bdf2e271..80de218fa 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -48,7 +48,7 @@ impl Display for SimpleType { } /// Trait of primitive types (SimpleType or ClassicType). -pub trait PrimType: 'static { +pub trait PrimType: std::fmt::Debug+'static { // may be updated with functions in future for necessary shared functionality // across ClassicType and SimpleType // currently used to constrain Container @@ -287,12 +287,12 @@ impl<'a> TryFrom<&'a SimpleType> for &'a ClassicType { #[cfg_attr(feature = "pyo3", pyclass)] #[non_exhaustive] #[serde(transparent)] -pub struct TypeRow where [T]: ToOwned + 'static { +pub struct TypeRow where [T]: ToOwned + 'static { /// The datatypes in the row. types: Cow<'static, [T]>, } -impl Display for TypeRow where [T]: ToOwned { +impl Display for TypeRow where [T]: ToOwned { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_char('[')?; display_list(self.types.as_ref(), f)?; @@ -301,7 +301,7 @@ impl Display for TypeRow where [T]: ToOwned { } #[cfg_attr(feature = "pyo3", pymethods)] -impl TypeRow where [T]: ToOwned { +impl TypeRow where [T]: ToOwned { /// Returns the number of types in the row. #[inline(always)] pub fn len(&self) -> usize { @@ -340,7 +340,7 @@ impl TypeRow { } } -impl TypeRow where [T]: ToOwned> { +impl TypeRow where [T]: ToOwned> { /// Create a new empty row. pub const fn new() -> Self { Self { @@ -371,14 +371,14 @@ impl TypeRow where [T]: ToOwned> { } } -impl Default for TypeRow -where [T]: ToOwned { +impl Default for TypeRow +where [T]: ToOwned> { fn default() -> Self { Self::new() } } -impl From for TypeRow +impl From for TypeRow where F: Into>, [T]: ToOwned @@ -390,7 +390,7 @@ where } } -impl Deref for TypeRow where [T]: ToOwned { +impl Deref for TypeRow where [T]: ToOwned { type Target = [T]; fn deref(&self) -> &Self::Target { @@ -398,7 +398,7 @@ impl Deref for TypeRow where [T]: ToOwned { } } -impl DerefMut for TypeRow where [T]: ToOwned { +impl DerefMut for TypeRow where [T]: ToOwned> { fn deref_mut(&mut self) -> &mut Self::Target { self.types.to_mut() } From ccfdb13ff9101b676ab3bcc7265c8c1301b45dfd Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 7 Jul 2023 17:46:03 +0100 Subject: [PATCH 09/47] More ToOwned - everything > --- src/types.rs | 2 +- src/types/simple.rs | 15 ++++++++------- src/types/simple/serialize.rs | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/types.rs b/src/types.rs index 19a0102a1..96039c024 100644 --- a/src/types.rs +++ b/src/types.rs @@ -329,7 +329,7 @@ impl SignatureDescription { fn row_zip<'a, T: std::fmt::Debug>( type_row: &'a TypeRow, name_row: &'a [SmolStr], - ) -> impl Iterator where [T]: ToOwned { + ) -> impl Iterator where [T]: ToOwned> { name_row .iter() .chain(&EmptyStringIterator) diff --git a/src/types/simple.rs b/src/types/simple.rs index 80de218fa..7d7c2f310 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -62,7 +62,7 @@ pub trait PrimType: std::fmt::Debug+'static { /// For algebraic types Sum, Tuple if one element of type row is linear, the /// overall type is too. #[derive(Clone, Debug, PartialEq, Eq)] -pub enum Container where [T]: ToOwned { +pub enum Container where [T]: ToOwned> { /// Variable sized list of T. List(Box), /// Hash map from hashable key type to value T. @@ -77,7 +77,7 @@ pub enum Container where [T]: ToOwned { Alias(SmolStr), } -impl Display for Container where [T]: ToOwned { +impl Display for Container where [T]: ToOwned> { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { Container::List(ty) => write!(f, "List({})", ty.as_ref()), @@ -287,12 +287,12 @@ impl<'a> TryFrom<&'a SimpleType> for &'a ClassicType { #[cfg_attr(feature = "pyo3", pyclass)] #[non_exhaustive] #[serde(transparent)] -pub struct TypeRow where [T]: ToOwned + 'static { +pub struct TypeRow where [T]: ToOwned> + 'static { /// The datatypes in the row. types: Cow<'static, [T]>, } -impl Display for TypeRow where [T]: ToOwned { +impl Display for TypeRow where [T]: ToOwned> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_char('[')?; display_list(self.types.as_ref(), f)?; @@ -301,7 +301,7 @@ impl Display for TypeRow where [T]: ToOwned { } #[cfg_attr(feature = "pyo3", pymethods)] -impl TypeRow where [T]: ToOwned { +impl TypeRow where [T]: ToOwned> { /// Returns the number of types in the row. #[inline(always)] pub fn len(&self) -> usize { @@ -381,7 +381,7 @@ where [T]: ToOwned> { impl From for TypeRow where F: Into>, - [T]: ToOwned + [T]: ToOwned> { fn from(types: F) -> Self { Self { @@ -390,7 +390,8 @@ where } } -impl Deref for TypeRow where [T]: ToOwned { + +impl Deref for TypeRow where [T]: ToOwned> { type Target = [T]; fn deref(&self) -> &Self::Target { diff --git a/src/types/simple/serialize.rs b/src/types/simple/serialize.rs index b4fea4490..867bd6285 100644 --- a/src/types/simple/serialize.rs +++ b/src/types/simple/serialize.rs @@ -65,7 +65,7 @@ pub(crate) enum SerSimpleType { }, } -impl> From> for SerSimpleType where [T]: ToOwned { +impl> From> for SerSimpleType where [T]: ToOwned> { fn from(value: Container) -> Self { match value { Container::Sum(inner) => SerSimpleType::Sum { From 76616a00d8f8124e8fe78cd861fe7c7ebb158ebd Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 7 Jul 2023 17:46:24 +0100 Subject: [PATCH 10/47] TypeRow has predicate_variant_rows as predicates are always Classical --- src/types/simple.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/types/simple.rs b/src/types/simple.rs index 7d7c2f310..0eb99cad6 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -327,14 +327,16 @@ impl TypeRow { pub fn purely_classical(&self) -> bool { self.types.iter().all(SimpleType::is_classical) } +} +impl TypeRow { #[inline] /// Return the type row of variants required to define a Sum of Tuples type /// given the rows of each tuple - pub fn predicate_variants_row(variant_rows: impl IntoIterator>) -> Self { + pub fn predicate_variants_row(variant_rows: impl IntoIterator>) -> Self { variant_rows .into_iter() - .map(|row| SimpleType::Classic(ClassicType::Container(Container::Tuple(Box::new(row))))) + .map(|row| ClassicType::Container(Container::Tuple(Box::new(row)))) .collect_vec() .into() } From edbbdf8980d5415de54c442d293160e6d4213549 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 7 Jul 2023 17:46:54 +0100 Subject: [PATCH 11/47] try_convert_elems for new_sum/new_tuple --- src/types/simple.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/types/simple.rs b/src/types/simple.rs index 0eb99cad6..cd230dfe5 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -219,6 +219,7 @@ impl SimpleType { pub fn new_sum(row: impl Into>) -> Self { let row = row.into(); if row.purely_classical() { + let row: TypeRow = row.try_convert_elems().unwrap(); Container::::Sum(Box::new(row)).into() } else { Container::::Sum(Box::new(row)).into() @@ -229,6 +230,7 @@ impl SimpleType { pub fn new_tuple(row: impl Into>) -> Self { let row = row.into(); if row.purely_classical() { + let row: TypeRow = row.try_convert_elems().unwrap(); Container::::Tuple(Box::new(row)).into() } else { Container::::Tuple(Box::new(row)).into() @@ -371,6 +373,11 @@ impl TypeRow where [T]: ToOwned> { pub fn get_mut(&mut self, offset: usize) -> Option<&mut T> { self.types.to_mut().get_mut(offset) } + + pub fn try_convert_elems>(self) -> Result, D::Error> where [D]: ToOwned> { + let elems: Vec = self.types.into_iter().map(|e| {let r = D::try_from(*e); r}).collect::>()?; + Ok(TypeRow::from(elems)) + } } impl Default for TypeRow From b5b39758134d41498d4a467bbab0fdaa6ebdc2a6 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 7 Jul 2023 17:47:29 +0100 Subject: [PATCH 12/47] Driveby use SimpleType::is_linear rather than lambda --- src/types/simple.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/simple.rs b/src/types/simple.rs index cd230dfe5..6a800f1f9 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -321,7 +321,7 @@ impl TypeRow { /// Returns whether the row contains only linear data. #[inline(always)] pub fn purely_linear(&self) -> bool { - self.types.iter().all(|typ| typ.is_linear()) + self.types.iter().all(SimpleType::is_linear) } /// Returns whether the row contains only classic data. From c48e4e709a016e2ef2f7a77a6fd57e555c0a263e Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 10 Jul 2023 09:18:23 +0100 Subject: [PATCH 13/47] TEMP turn off types/simple/serialize.rs --- src/types/simple.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/types/simple.rs b/src/types/simple.rs index 6a800f1f9..9bce669dd 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -21,7 +21,6 @@ use crate::{resource::ResourceSet, type_row}; // // TODO: Compare performance vs flattening this into a single enum #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -#[serde(from = "serialize::SerSimpleType", into = "serialize::SerSimpleType")] #[non_exhaustive] pub enum SimpleType { /// A type containing only classical data. Elements of this type can be copied. @@ -31,11 +30,10 @@ pub enum SimpleType { /// A linear opaque type that can be downcasted by the extensions that define it. Qpaque(CustomType), /// A nested definition containing other linear types (possibly as well as classical ones) + #[serde(skip)] Qontainer(Container), } -mod serialize; - impl Display for SimpleType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { From 5b080a2ae480fa03862f5cb051915c34dc6bffca Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 10 Jul 2023 09:21:12 +0100 Subject: [PATCH 14/47] Constant Sums must be all-classic; other fixes --- src/ops/constant.rs | 10 +++++----- src/ops/dataflow.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ops/constant.rs b/src/ops/constant.rs index 6881299a7..4603d8c15 100644 --- a/src/ops/constant.rs +++ b/src/ops/constant.rs @@ -59,9 +59,9 @@ pub enum ConstValue { /// A constant specifying a variant of a Sum type. Sum { tag: usize, - // The *type* could have linear types in other variants, so long as - // the value was of another variant - variants: TypeRow, + // We require the type to be entirely Classic (i.e. we don't allow + // a classic variant of a Sum with other variants that are linear) + variants: TypeRow, val: Box, }, /// A tuple of constant values. @@ -124,7 +124,7 @@ impl ConstValue { Self::Tuple(vals) => { let row: Vec<_> = vals .iter() - .map(|val| SimpleType::Classic(val.const_type())) + .map(|val| val.const_type()) .collect(); ClassicType::Container(Container::Tuple(Box::new(row.into()))) } @@ -175,7 +175,7 @@ impl ConstValue { } /// Constant Sum over Tuples, used as predicates. - pub fn predicate(tag: usize, variant_rows: impl IntoIterator>) -> Self { + pub fn predicate(tag: usize, variant_rows: impl IntoIterator>) -> Self { let variants = TypeRow::predicate_variants_row(variant_rows); assert!(variants.get(tag) == Some(&SimpleType::new_unit())); ConstValue::Sum { diff --git a/src/ops/dataflow.rs b/src/ops/dataflow.rs index 0908e0e15..dfffe303e 100644 --- a/src/ops/dataflow.rs +++ b/src/ops/dataflow.rs @@ -221,7 +221,7 @@ impl DataflowOpTrait for LoadConstant { Signature::new( TypeRow::new(), vec![SimpleType::Classic(self.datatype.clone())], - vec![SimpleType::Classic(self.datatype.clone())], + vec![self.datatype.clone()], ) } } From 83b9736d30c24cc38ce186f0878934bc053c1a3d Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 10 Jul 2023 12:56:10 +0100 Subject: [PATCH 15/47] Add TypeRow::into_owned; Remove ConstTypeError::LinearTypeDisallowed; cargo build compiles --- src/builder/build_traits.rs | 17 +++++++++-------- src/builder/cfg.rs | 12 ++++++------ src/builder/conditional.rs | 4 ++-- src/builder/tail_loop.rs | 6 +++--- src/extensions/rotation.rs | 2 +- src/hugr/typecheck.rs | 17 ++++------------- src/ops/constant.rs | 4 ++-- src/ops/controlflow.rs | 32 ++++++++++++++------------------ src/ops/validate.rs | 6 +++--- src/types.rs | 2 +- src/types/simple.rs | 23 ++++++++++++++--------- 11 files changed, 59 insertions(+), 66 deletions(-) diff --git a/src/builder/build_traits.rs b/src/builder/build_traits.rs index 273bb69f4..4816c0a6c 100644 --- a/src/builder/build_traits.rs +++ b/src/builder/build_traits.rs @@ -16,7 +16,7 @@ use crate::{ types::EdgeKind, }; -use crate::types::{Signature, SimpleType, TypeRow}; +use crate::types::{Signature, SimpleType, TypeRow, ClassicType}; use itertools::Itertools; @@ -281,7 +281,7 @@ pub trait Dataflow: Container { ) -> Result, BuildError> { let (input_types, input_wires): (Vec, Vec) = inputs.into_iter().unzip(); - let inputs: TypeRow = input_types.into(); + let inputs: TypeRow = input_types.into(); let (cfg_node, _) = add_op_with_wires( self, @@ -334,11 +334,11 @@ pub trait Dataflow: Container { /// the [`ops::TailLoop`] node. fn tail_loop_builder( &mut self, - just_inputs: impl IntoIterator, + just_inputs: impl IntoIterator, inputs_outputs: impl IntoIterator, - just_out_types: TypeRow, + just_out_types: TypeRow, ) -> Result, BuildError> { - let (input_types, mut input_wires): (Vec, Vec) = + let (input_types, mut input_wires): (Vec, Vec) = just_inputs.into_iter().unzip(); let (rest_types, rest_input_wires): (Vec, Vec) = inputs_outputs.into_iter().unzip(); @@ -368,7 +368,7 @@ pub trait Dataflow: Container { /// the Conditional node. fn conditional_builder( &mut self, - (predicate_inputs, predicate_wire): (impl IntoIterator>, Wire), + (predicate_inputs, predicate_wire): (impl IntoIterator>, Wire), other_inputs: impl IntoIterator, output_types: TypeRow, ) -> Result, BuildError> { @@ -377,7 +377,7 @@ pub trait Dataflow: Container { other_inputs.into_iter().unzip(); input_wires.extend(rest_input_wires); - let inputs: TypeRow = input_types.into(); + let inputs: TypeRow = input_types.into(); let predicate_inputs: Vec<_> = predicate_inputs.into_iter().collect(); let n_cases = predicate_inputs.len(); let n_out_wires = output_types.len(); @@ -470,11 +470,12 @@ pub trait Dataflow: Container { fn make_predicate( &mut self, tag: usize, - predicate_variants: impl IntoIterator>, + predicate_variants: impl IntoIterator>, values: impl IntoIterator, ) -> Result { let tuple = self.make_tuple(values)?; let variants = TypeRow::predicate_variants_row(predicate_variants); + let variants = variants.into_owned().into_iter().map(SimpleType::Classic).collect::>().into(); let make_op = self.add_dataflow_op(LeafOp::Tag { tag, variants }, vec![tuple])?; Ok(make_op.out_wire(0)) } diff --git a/src/builder/cfg.rs b/src/builder/cfg.rs index c1a96d0d5..3958b1aec 100644 --- a/src/builder/cfg.rs +++ b/src/builder/cfg.rs @@ -7,7 +7,7 @@ use super::{ BasicBlockID, BuildError, CfgID, Container, Dataflow, HugrBuilder, Wire, }; -use crate::{hugr::view::HugrView, type_row, types::SimpleType}; +use crate::{hugr::view::HugrView, type_row, types::{SimpleType, ClassicType}}; use crate::ops::handle::NodeHandle; use crate::ops::{self, BasicBlock, OpType}; @@ -123,7 +123,7 @@ impl + AsRef> CFGBuilder { pub fn block_builder( &mut self, inputs: TypeRow, - predicate_variants: Vec>, + predicate_variants: Vec>, other_outputs: TypeRow, ) -> Result, BuildError> { self.any_block_builder(inputs, predicate_variants, other_outputs, false) @@ -132,7 +132,7 @@ impl + AsRef> CFGBuilder { fn any_block_builder( &mut self, inputs: TypeRow, - predicate_variants: Vec>, + predicate_variants: Vec>, other_outputs: TypeRow, entry: bool, ) -> Result, BuildError> { @@ -182,7 +182,7 @@ impl + AsRef> CFGBuilder { /// This function will return an error if an entry block has already been built. pub fn entry_builder( &mut self, - predicate_variants: Vec>, + predicate_variants: Vec>, other_outputs: TypeRow, ) -> Result, BuildError> { let inputs = self @@ -244,7 +244,7 @@ impl + AsRef> BlockBuilder { fn create( base: B, block_n: Node, - predicate_variants: Vec>, + predicate_variants: Vec>, other_outputs: TypeRow, inputs: TypeRow, ) -> Result { @@ -276,7 +276,7 @@ impl BlockBuilder { /// Initialize a [`BasicBlock::DFB`] rooted HUGR builder pub fn new( inputs: impl Into>, - predicate_variants: impl IntoIterator>, + predicate_variants: impl IntoIterator>, other_outputs: impl Into>, ) -> Result { let inputs = inputs.into(); diff --git a/src/builder/conditional.rs b/src/builder/conditional.rs index c6975f8e6..9aeb1dcb6 100644 --- a/src/builder/conditional.rs +++ b/src/builder/conditional.rs @@ -1,5 +1,5 @@ use crate::hugr::view::HugrView; -use crate::types::{Signature, TypeRow, SimpleType}; +use crate::types::{Signature, TypeRow, SimpleType, ClassicType}; use crate::ops; use crate::ops::handle::CaseID; @@ -146,7 +146,7 @@ impl HugrBuilder for ConditionalBuilder { impl ConditionalBuilder { /// Initialize a Conditional rooted HUGR builder pub fn new( - predicate_inputs: impl IntoIterator>, + predicate_inputs: impl IntoIterator>, other_inputs: impl Into>, outputs: impl Into>, ) -> Result { diff --git a/src/builder/tail_loop.rs b/src/builder/tail_loop.rs index 6e6022f33..8efdfd3f8 100644 --- a/src/builder/tail_loop.rs +++ b/src/builder/tail_loop.rs @@ -1,7 +1,7 @@ use crate::ops::{self, OpType}; use crate::hugr::view::HugrView; -use crate::types::{Signature, TypeRow, SimpleType}; +use crate::types::{Signature, TypeRow, SimpleType, ClassicType}; use crate::{Hugr, Node}; use super::build_traits::SubContainer; @@ -72,9 +72,9 @@ impl + AsRef> TailLoopBuilder { impl TailLoopBuilder { /// Initialize new builder for a [`ops::TailLoop`] rooted HUGR pub fn new( - just_inputs: impl Into>, + just_inputs: impl Into>, inputs_outputs: impl Into>, - just_outputs: impl Into>, + just_outputs: impl Into>, ) -> Result { let tail_loop = ops::TailLoop { just_inputs: just_inputs.into(), diff --git a/src/extensions/rotation.rs b/src/extensions/rotation.rs index d8f36f82f..ed648dab9 100644 --- a/src/extensions/rotation.rs +++ b/src/extensions/rotation.rs @@ -110,7 +110,7 @@ impl CustomSignatureFunc for AngleAdd { _arg_values: &[TypeArg], _misc: &HashMap, ) -> Result<(TypeRow, TypeRow, ResourceSet), SignatureError> { - let t: TypeRow = vec![SimpleType::Classic( + let t: TypeRow = vec![SimpleType::Classic( Into::::into(Type::Angle).into(), )] .into(); diff --git a/src/hugr/typecheck.rs b/src/hugr/typecheck.rs index af288e255..accf5352a 100644 --- a/src/hugr/typecheck.rs +++ b/src/hugr/typecheck.rs @@ -6,7 +6,7 @@ use lazy_static::lazy_static; use std::collections::HashSet; use crate::hugr::*; -use crate::types::{SimpleType, TypeRow}; +use crate::types::TypeRow; // For static typechecking use crate::ops::ConstValue; @@ -43,9 +43,6 @@ pub enum ConstTypeError { /// The length of the tuple value doesn't match the length of the tuple type #[error("Tuple of wrong length")] TupleWrongLength, - /// Const values aren't allowed to be linear - #[error("Linear types not allowed in const nodes")] - LinearTypeDisallowed, /// Tag for a sum value exceeded the number of variants #[error("Tag of Sum value is invalid")] InvalidSumTag, @@ -56,7 +53,7 @@ pub enum ConstTypeError { /// A mismatch between the embedded type and the type we're checking /// against, as above, but for rows instead of simple types #[error("Type mismatch for const - expected {0}, found {1}")] - TypeRowMismatch(TypeRow, TypeRow), + TypeRowMismatch(TypeRow, TypeRow), } lazy_static! { @@ -107,10 +104,7 @@ pub fn typecheck_const(typ: &ClassicType, val: &ConstValue) -> Result<(), ConstT return Err(ConstTypeError::TupleWrongLength); } for (ty, tm) in row.iter().zip(xs.iter()) { - match ty { - SimpleType::Classic(ty) => typecheck_const(ty, tm)?, - _ => return Err(ConstTypeError::LinearTypeDisallowed), - } + typecheck_const(ty, tm)? } Ok(()) } @@ -125,10 +119,7 @@ pub fn typecheck_const(typ: &ClassicType, val: &ConstValue) -> Result<(), ConstT )); } let ty = variants.get(*tag).unwrap(); - match ty { - SimpleType::Classic(ty) => typecheck_const(ty, val.as_ref()), - _ => Err(ConstTypeError::LinearTypeDisallowed), - } + typecheck_const(ty, val.as_ref()) } _ => Err(ConstTypeError::Unimplemented(ty.clone())), }, diff --git a/src/ops/constant.rs b/src/ops/constant.rs index 4603d8c15..fba303409 100644 --- a/src/ops/constant.rs +++ b/src/ops/constant.rs @@ -177,7 +177,7 @@ impl ConstValue { /// Constant Sum over Tuples, used as predicates. pub fn predicate(tag: usize, variant_rows: impl IntoIterator>) -> Self { let variants = TypeRow::predicate_variants_row(variant_rows); - assert!(variants.get(tag) == Some(&SimpleType::new_unit())); + assert!(variants.get(tag) == Some(&ClassicType::new_unit())); ConstValue::Sum { tag, variants, @@ -186,7 +186,7 @@ impl ConstValue { } /// Constant Sum over Tuples with just one variant - pub fn unary_predicate(row: impl Into>) -> Self { + pub fn unary_predicate(row: impl Into>) -> Self { Self::predicate(0, [row.into()]) } diff --git a/src/ops/controlflow.rs b/src/ops/controlflow.rs index 412aacb39..49681b458 100644 --- a/src/ops/controlflow.rs +++ b/src/ops/controlflow.rs @@ -2,7 +2,7 @@ use smol_str::SmolStr; -use crate::types::{EdgeKind, Signature, SimpleType, TypeRow}; +use crate::types::{EdgeKind, Signature, SimpleType, TypeRow, ClassicType}; use super::dataflow::DataflowOpTrait; use super::tag::OpTag; @@ -12,9 +12,9 @@ use super::{impl_op_name, OpName, OpTrait}; #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct TailLoop { /// Types that are only input - pub just_inputs: TypeRow, + pub just_inputs: TypeRow, /// Types that are only output - pub just_outputs: TypeRow, + pub just_outputs: TypeRow, /// Types that are appended to both input and output pub rest: TypeRow, } @@ -32,9 +32,8 @@ impl DataflowOpTrait for TailLoop { fn signature(&self) -> Signature { let [inputs, outputs] = - [self.just_inputs.clone(), self.just_outputs.clone()].map(|mut row| { - row.to_mut().extend(self.rest.iter().cloned()); - row + [&self.just_inputs, &self.just_outputs].map(|row| { + predicate_first(row, &self.rest) }); Signature::new_df(inputs, outputs) } @@ -52,9 +51,7 @@ impl TailLoop { /// Build the input TypeRow of the child graph of a TailLoop node. pub(crate) fn body_input_row(&self) -> TypeRow { - let mut inputs = self.just_inputs.clone(); - inputs.to_mut().extend_from_slice(&self.rest); - inputs + predicate_first(&self.just_inputs, &self.rest) } } @@ -62,7 +59,7 @@ impl TailLoop { #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct Conditional { /// The possible rows of the predicate input - pub predicate_inputs: Vec>, + pub predicate_inputs: Vec>, /// Remaining input types pub other_inputs: TypeRow, /// Output types @@ -92,10 +89,7 @@ impl DataflowOpTrait for Conditional { impl Conditional { /// Build the input TypeRow of the nth child graph of a Conditional node. pub(crate) fn case_input_row(&self, case: usize) -> Option> { - let mut inputs = self.predicate_inputs.get(case)?.clone(); - - inputs.to_mut().extend_from_slice(&self.other_inputs); - Some(inputs) + Some(predicate_first(self.predicate_inputs.get(case)?, &self.other_inputs)) } } @@ -132,7 +126,7 @@ pub enum BasicBlock { DFB { inputs: TypeRow, other_outputs: TypeRow, - predicate_variants: Vec>, + predicate_variants: Vec>, }, /// The single exit node of the CFG, has no children, /// stores the types of the CFG node output. @@ -192,9 +186,7 @@ impl BasicBlock { other_outputs: outputs, .. } => { - let mut row = predicate_variants.get(successor)?.clone(); - row.to_mut().extend_from_slice(outputs); - Some(row) + Some(predicate_first(predicate_variants.get(successor)?, outputs)) } BasicBlock::Exit { .. } => panic!("Exit should have no successors"), } @@ -231,3 +223,7 @@ impl Case { &self.signature.output } } + +fn predicate_first(pred: &TypeRow, rest: &TypeRow) -> TypeRow { + TypeRow::from(pred.iter().cloned().map(SimpleType::Classic).chain(rest.iter().cloned()).collect::>()) +} \ No newline at end of file diff --git a/src/ops/validate.rs b/src/ops/validate.rs index 7fdde519b..b158b722b 100644 --- a/src/ops/validate.rs +++ b/src/ops/validate.rs @@ -10,7 +10,7 @@ use itertools::Itertools; use portgraph::{NodeIndex, PortOffset}; use thiserror::Error; -use crate::types::{SimpleType, TypeRow}; +use crate::types::{SimpleType, TypeRow, ClassicType}; use crate::Direction; use super::{impl_validate_op, tag::OpTag, BasicBlock, OpTrait, OpType, ValidateOp}; @@ -255,7 +255,7 @@ pub enum ChildrenValidationError { child: NodeIndex, expected_count: usize, actual_count: usize, - actual_predicate_rows: Vec>, + actual_predicate_rows: Vec>, }, } @@ -342,7 +342,7 @@ impl ValidateOp for BasicBlock { other_outputs: outputs, } => { let predicate_type = SimpleType::new_predicate(predicate_variants.clone()); - let node_outputs: TypeRow = [&[predicate_type], outputs.as_ref()].concat().into(); + let node_outputs: TypeRow = [&[predicate_type], outputs.as_ref()].concat().into(); validate_io_nodes(inputs, &node_outputs, "basic block graph", children) } // Exit nodes do not have children diff --git a/src/types.rs b/src/types.rs index 96039c024..196390080 100644 --- a/src/types.rs +++ b/src/types.rs @@ -362,7 +362,7 @@ impl SignatureDescription { pub fn static_input_zip<'a>( &'a self, signature: &'a Signature, - ) -> impl Iterator { + ) -> impl Iterator { Self::row_zip(&signature.static_input, &self.static_input) } } diff --git a/src/types/simple.rs b/src/types/simple.rs index 9bce669dd..3bce0a3ea 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -153,6 +153,13 @@ impl ClassicType { Self::int::<1>() } + /// New unit type, defined as an empty Tuple. + pub fn new_unit() -> Self { + Self::Container(Container::Tuple(Box::new( + TypeRow::new(), + ))) + } + /// New Sum of Tuple types, used as predicates in branching. /// Tuple rows are defined in order by input rows. pub fn new_predicate(variant_rows: impl IntoIterator>) -> Self { @@ -235,13 +242,6 @@ impl SimpleType { } } - /// New unit type, defined as an empty Tuple. - pub fn new_unit() -> Self { - Self::Classic(ClassicType::Container(Container::Tuple(Box::new( - TypeRow::new(), - )))) - } - /// New Sum of Tuple types, used as predicates in branching. /// Tuple rows are defined in order by input rows. pub fn new_predicate(variant_rows: impl IntoIterator>) -> Self { @@ -360,6 +360,11 @@ impl TypeRow where [T]: ToOwned> { self.types.to_mut() } + /// Allow access (consumption) of the contained elements + pub fn into_owned(self) -> Vec { + self.types.into_owned() + } + #[inline(always)] /// Returns the port type given an offset. Returns `None` if the offset is out of bounds. pub fn get(&self, offset: usize) -> Option<&T> { @@ -372,8 +377,8 @@ impl TypeRow where [T]: ToOwned> { self.types.to_mut().get_mut(offset) } - pub fn try_convert_elems>(self) -> Result, D::Error> where [D]: ToOwned> { - let elems: Vec = self.types.into_iter().map(|e| {let r = D::try_from(*e); r}).collect::>()?; + fn try_convert_elems>(self) -> Result, D::Error> where [D]: ToOwned> { + let elems: Vec = self.into_owned().into_iter().map(D::try_from).collect::>()?; Ok(TypeRow::from(elems)) } } From 93b030a1698f17d48e41ccb87902a05cccc82841 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 10 Jul 2023 13:14:26 +0100 Subject: [PATCH 16/47] Fix tests, except serialization of course! --- src/builder/build_traits.rs | 9 ++++- src/builder/cfg.rs | 20 +++++++--- src/builder/conditional.rs | 7 +++- src/builder/dataflow.rs | 2 +- src/builder/tail_loop.rs | 12 ++++-- src/macros.rs | 33 +++++++++++++++++ src/ops/constant.rs | 10 ++--- src/ops/controlflow.rs | 25 ++++++++----- src/ops/validate.rs | 5 ++- src/resource.rs | 2 +- src/types.rs | 10 ++++- src/types/simple.rs | 74 +++++++++++++++++++++++++++---------- 12 files changed, 155 insertions(+), 54 deletions(-) diff --git a/src/builder/build_traits.rs b/src/builder/build_traits.rs index 4816c0a6c..19bdd4474 100644 --- a/src/builder/build_traits.rs +++ b/src/builder/build_traits.rs @@ -16,7 +16,7 @@ use crate::{ types::EdgeKind, }; -use crate::types::{Signature, SimpleType, TypeRow, ClassicType}; +use crate::types::{ClassicType, Signature, SimpleType, TypeRow}; use itertools::Itertools; @@ -475,7 +475,12 @@ pub trait Dataflow: Container { ) -> Result { let tuple = self.make_tuple(values)?; let variants = TypeRow::predicate_variants_row(predicate_variants); - let variants = variants.into_owned().into_iter().map(SimpleType::Classic).collect::>().into(); + let variants = variants + .into_owned() + .into_iter() + .map(SimpleType::Classic) + .collect::>() + .into(); let make_op = self.add_dataflow_op(LeafOp::Tag { tag, variants }, vec![tuple])?; Ok(make_op.out_wire(0)) } diff --git a/src/builder/cfg.rs b/src/builder/cfg.rs index 3958b1aec..1ebd4ddc4 100644 --- a/src/builder/cfg.rs +++ b/src/builder/cfg.rs @@ -7,7 +7,11 @@ use super::{ BasicBlockID, BuildError, CfgID, Container, Dataflow, HugrBuilder, Wire, }; -use crate::{hugr::view::HugrView, type_row, types::{SimpleType, ClassicType}}; +use crate::{ + hugr::view::HugrView, + type_row, + types::{ClassicType, SimpleType}, +}; use crate::ops::handle::NodeHandle; use crate::ops::{self, BasicBlock, OpType}; @@ -54,7 +58,10 @@ impl + AsRef> SubContainer for CFGBuilder { impl CFGBuilder { /// New CFG rooted HUGR builder - pub fn new(input: impl Into>, output: impl Into>) -> Result { + pub fn new( + input: impl Into>, + output: impl Into>, + ) -> Result { let input = input.into(); let output = output.into(); let cfg_op = ops::CFG { @@ -298,11 +305,11 @@ impl BlockBuilder { mod test { use std::collections::HashSet; - use cool_asserts::assert_matches; - use crate::builder::build_traits::HugrBuilder; use crate::builder::{DataflowSubContainer, ModuleBuilder}; + use crate::macros::classic_row; use crate::{builder::test::NAT, ops::ConstValue, type_row, types::Signature}; + use cool_asserts::assert_matches; use super::*; #[test] @@ -372,7 +379,10 @@ mod test { fn build_basic_cfg + AsRef>( cfg_builder: &mut CFGBuilder, ) -> Result<(), BuildError> { - let sum2_variants = vec![type_row![NAT], type_row![NAT]]; + let sum2_variants = vec![ + classic_row![ClassicType::i64()], + classic_row![ClassicType::i64()], + ]; let mut entry_b = cfg_builder.entry_builder(sum2_variants.clone(), type_row![])?; let entry = { let [inw] = entry_b.input_wires_arr(); diff --git a/src/builder/conditional.rs b/src/builder/conditional.rs index 9aeb1dcb6..eb2f54c78 100644 --- a/src/builder/conditional.rs +++ b/src/builder/conditional.rs @@ -1,5 +1,5 @@ use crate::hugr::view::HugrView; -use crate::types::{Signature, TypeRow, SimpleType, ClassicType}; +use crate::types::{ClassicType, Signature, SimpleType, TypeRow}; use crate::ops; use crate::ops::handle::CaseID; @@ -176,7 +176,10 @@ impl ConditionalBuilder { impl CaseBuilder { /// Initialize a Case rooted HUGR - pub fn new(input: impl Into>, output: impl Into>) -> Result { + pub fn new( + input: impl Into>, + output: impl Into>, + ) -> Result { let input = input.into(); let output = output.into(); let signature = Signature::new_df(input, output); diff --git a/src/builder/dataflow.rs b/src/builder/dataflow.rs index cb1aeb7ed..087fa0b92 100644 --- a/src/builder/dataflow.rs +++ b/src/builder/dataflow.rs @@ -7,7 +7,7 @@ use std::marker::PhantomData; use crate::hugr::{HugrView, ValidationError}; use crate::ops; -use crate::types::{Signature, TypeRow, SimpleType}; +use crate::types::{Signature, SimpleType, TypeRow}; use crate::Node; use crate::{hugr::HugrMut, Hugr}; diff --git a/src/builder/tail_loop.rs b/src/builder/tail_loop.rs index 8efdfd3f8..30485b662 100644 --- a/src/builder/tail_loop.rs +++ b/src/builder/tail_loop.rs @@ -1,7 +1,7 @@ use crate::ops::{self, OpType}; use crate::hugr::view::HugrView; -use crate::types::{Signature, TypeRow, SimpleType, ClassicType}; +use crate::types::{ClassicType, Signature, SimpleType, TypeRow}; use crate::{Hugr, Node}; use super::build_traits::SubContainer; @@ -96,6 +96,7 @@ mod test { test::{BIT, NAT}, DataflowSubContainer, HugrBuilder, ModuleBuilder, }, + classic_row, hugr::ValidationError, ops::ConstValue, type_row, @@ -107,7 +108,7 @@ mod test { #[test] fn basic_loop() -> Result<(), BuildError> { let build_result: Result = { - let mut loop_b = TailLoopBuilder::new(vec![], vec![BIT], type_row![NAT])?; + let mut loop_b = TailLoopBuilder::new(vec![], vec![BIT], vec![ClassicType::i64()])?; let [i1] = loop_b.input_wires_arr(); let const_wire = loop_b.add_load_const(ConstValue::i64(1))?; @@ -129,8 +130,11 @@ mod test { let _fdef = { let [b1] = fbuild.input_wires_arr(); let loop_id = { - let mut loop_b = - fbuild.tail_loop_builder(vec![(BIT, b1)], vec![], type_row![NAT])?; + let mut loop_b = fbuild.tail_loop_builder( + vec![(ClassicType::bit(), b1)], + vec![], + classic_row![ClassicType::i64()], + )?; let signature = loop_b.loop_signature()?.clone(); let const_wire = loop_b.add_load_const(ConstValue::true_val())?; let [b1] = loop_b.input_wires_arr(); diff --git a/src/macros.rs b/src/macros.rs index f33028794..719369f19 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -77,5 +77,38 @@ macro_rules! type_row { } }; } + +/// Like [type_row!] but for rows of [ClassicType]s +/// +/// [ClassicType]: types::ClassicType +#[allow(unused_macros)] +#[macro_export] +macro_rules! classic_row { + () => { + { + $crate::types::TypeRow::new() + } + }; + ($($t:expr),+ $(,)?) => { + { + use $crate::types; + static ROW: &[types::ClassicType] = &[$($t),*]; + let row: types::TypeRow<_> = ROW.into(); + row + } + }; + ($t:expr; $n:expr) => { + { + use $crate::types; + static ROW: &[types::ClassicType] = &[$t; $n]; + let row: types::TypeRow<_> = ROW.into(); + row + } + }; +} + #[allow(unused_imports)] pub use type_row; + +#[allow(unused_imports)] +pub use classic_row; diff --git a/src/ops/constant.rs b/src/ops/constant.rs index fba303409..4820fb4c4 100644 --- a/src/ops/constant.rs +++ b/src/ops/constant.rs @@ -122,10 +122,7 @@ impl ConstValue { ClassicType::Container(Container::Sum(Box::new(variants.clone()))) } Self::Tuple(vals) => { - let row: Vec<_> = vals - .iter() - .map(|val| val.const_type()) - .collect(); + let row: Vec<_> = vals.iter().map(|val| val.const_type()).collect(); ClassicType::Container(Container::Tuple(Box::new(row.into()))) } Self::F64(_) => ClassicType::F64, @@ -175,7 +172,10 @@ impl ConstValue { } /// Constant Sum over Tuples, used as predicates. - pub fn predicate(tag: usize, variant_rows: impl IntoIterator>) -> Self { + pub fn predicate( + tag: usize, + variant_rows: impl IntoIterator>, + ) -> Self { let variants = TypeRow::predicate_variants_row(variant_rows); assert!(variants.get(tag) == Some(&ClassicType::new_unit())); ConstValue::Sum { diff --git a/src/ops/controlflow.rs b/src/ops/controlflow.rs index 49681b458..12025f0a2 100644 --- a/src/ops/controlflow.rs +++ b/src/ops/controlflow.rs @@ -2,7 +2,7 @@ use smol_str::SmolStr; -use crate::types::{EdgeKind, Signature, SimpleType, TypeRow, ClassicType}; +use crate::types::{ClassicType, EdgeKind, Signature, SimpleType, TypeRow}; use super::dataflow::DataflowOpTrait; use super::tag::OpTag; @@ -32,9 +32,7 @@ impl DataflowOpTrait for TailLoop { fn signature(&self) -> Signature { let [inputs, outputs] = - [&self.just_inputs, &self.just_outputs].map(|row| { - predicate_first(row, &self.rest) - }); + [&self.just_inputs, &self.just_outputs].map(|row| predicate_first(row, &self.rest)); Signature::new_df(inputs, outputs) } } @@ -89,7 +87,10 @@ impl DataflowOpTrait for Conditional { impl Conditional { /// Build the input TypeRow of the nth child graph of a Conditional node. pub(crate) fn case_input_row(&self, case: usize) -> Option> { - Some(predicate_first(self.predicate_inputs.get(case)?, &self.other_inputs)) + Some(predicate_first( + self.predicate_inputs.get(case)?, + &self.other_inputs, + )) } } @@ -185,9 +186,7 @@ impl BasicBlock { predicate_variants, other_outputs: outputs, .. - } => { - Some(predicate_first(predicate_variants.get(successor)?, outputs)) - } + } => Some(predicate_first(predicate_variants.get(successor)?, outputs)), BasicBlock::Exit { .. } => panic!("Exit should have no successors"), } } @@ -225,5 +224,11 @@ impl Case { } fn predicate_first(pred: &TypeRow, rest: &TypeRow) -> TypeRow { - TypeRow::from(pred.iter().cloned().map(SimpleType::Classic).chain(rest.iter().cloned()).collect::>()) -} \ No newline at end of file + TypeRow::from( + pred.iter() + .cloned() + .map(SimpleType::Classic) + .chain(rest.iter().cloned()) + .collect::>(), + ) +} diff --git a/src/ops/validate.rs b/src/ops/validate.rs index b158b722b..54ce89157 100644 --- a/src/ops/validate.rs +++ b/src/ops/validate.rs @@ -10,7 +10,7 @@ use itertools::Itertools; use portgraph::{NodeIndex, PortOffset}; use thiserror::Error; -use crate::types::{SimpleType, TypeRow, ClassicType}; +use crate::types::{ClassicType, SimpleType, TypeRow}; use crate::Direction; use super::{impl_validate_op, tag::OpTag, BasicBlock, OpTrait, OpType, ValidateOp}; @@ -342,7 +342,8 @@ impl ValidateOp for BasicBlock { other_outputs: outputs, } => { let predicate_type = SimpleType::new_predicate(predicate_variants.clone()); - let node_outputs: TypeRow = [&[predicate_type], outputs.as_ref()].concat().into(); + let node_outputs: TypeRow = + [&[predicate_type], outputs.as_ref()].concat().into(); validate_io_nodes(inputs, &node_outputs, "basic block graph", children) } // Exit nodes do not have children diff --git a/src/resource.rs b/src/resource.rs index 73b50a1f0..2bd12cd1c 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -12,11 +12,11 @@ use smol_str::SmolStr; use thiserror::Error; use crate::types::type_param::{check_type_arg, TypeArgError}; -use crate::types::{TypeRow, SimpleType}; use crate::types::{ type_param::{TypeArg, TypeParam}, Signature, SignatureDescription, }; +use crate::types::{SimpleType, TypeRow}; use crate::Hugr; /// Trait for resources to provide custom binary code for computing signature. diff --git a/src/types.rs b/src/types.rs index 196390080..d370edce6 100644 --- a/src/types.rs +++ b/src/types.rs @@ -253,7 +253,10 @@ impl Signature { } /// Create a new signature with only dataflow inputs and outputs. - pub fn new_df(input: impl Into>, output: impl Into>) -> Self { + pub fn new_df( + input: impl Into>, + output: impl Into>, + ) -> Self { Signature::new(input, output, type_row![]) } } @@ -329,7 +332,10 @@ impl SignatureDescription { fn row_zip<'a, T: std::fmt::Debug>( type_row: &'a TypeRow, name_row: &'a [SmolStr], - ) -> impl Iterator where [T]: ToOwned> { + ) -> impl Iterator + where + [T]: ToOwned>, + { name_row .iter() .chain(&EmptyStringIterator) diff --git a/src/types/simple.rs b/src/types/simple.rs index 3bce0a3ea..17e677fd0 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -46,7 +46,7 @@ impl Display for SimpleType { } /// Trait of primitive types (SimpleType or ClassicType). -pub trait PrimType: std::fmt::Debug+'static { +pub trait PrimType: std::fmt::Debug + 'static { // may be updated with functions in future for necessary shared functionality // across ClassicType and SimpleType // currently used to constrain Container @@ -60,7 +60,10 @@ pub trait PrimType: std::fmt::Debug+'static { /// For algebraic types Sum, Tuple if one element of type row is linear, the /// overall type is too. #[derive(Clone, Debug, PartialEq, Eq)] -pub enum Container where [T]: ToOwned> { +pub enum Container +where + [T]: ToOwned>, +{ /// Variable sized list of T. List(Box), /// Hash map from hashable key type to value T. @@ -75,7 +78,10 @@ pub enum Container where [T]: ToOwned> { Alias(SmolStr), } -impl Display for Container where [T]: ToOwned> { +impl Display for Container +where + [T]: ToOwned>, +{ fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { Container::List(ty) => write!(f, "List({})", ty.as_ref()), @@ -155,9 +161,7 @@ impl ClassicType { /// New unit type, defined as an empty Tuple. pub fn new_unit() -> Self { - Self::Container(Container::Tuple(Box::new( - TypeRow::new(), - ))) + Self::Container(Container::Tuple(Box::new(TypeRow::new()))) } /// New Sum of Tuple types, used as predicates in branching. @@ -287,12 +291,18 @@ impl<'a> TryFrom<&'a SimpleType> for &'a ClassicType { #[cfg_attr(feature = "pyo3", pyclass)] #[non_exhaustive] #[serde(transparent)] -pub struct TypeRow where [T]: ToOwned> + 'static { +pub struct TypeRow +where + [T]: ToOwned> + 'static, +{ /// The datatypes in the row. types: Cow<'static, [T]>, } -impl Display for TypeRow where [T]: ToOwned> { +impl Display for TypeRow +where + [T]: ToOwned>, +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_char('[')?; display_list(self.types.as_ref(), f)?; @@ -301,7 +311,10 @@ impl Display for TypeRow where [T]: ToOwned TypeRow where [T]: ToOwned> { +impl TypeRow +where + [T]: ToOwned>, +{ /// Returns the number of types in the row. #[inline(always)] pub fn len(&self) -> usize { @@ -333,7 +346,9 @@ impl TypeRow { #[inline] /// Return the type row of variants required to define a Sum of Tuples type /// given the rows of each tuple - pub fn predicate_variants_row(variant_rows: impl IntoIterator>) -> Self { + pub fn predicate_variants_row( + variant_rows: impl IntoIterator>, + ) -> Self { variant_rows .into_iter() .map(|row| ClassicType::Container(Container::Tuple(Box::new(row)))) @@ -342,7 +357,10 @@ impl TypeRow { } } -impl TypeRow where [T]: ToOwned> { +impl TypeRow +where + [T]: ToOwned>, +{ /// Create a new empty row. pub const fn new() -> Self { Self { @@ -377,33 +395,46 @@ impl TypeRow where [T]: ToOwned> { self.types.to_mut().get_mut(offset) } - fn try_convert_elems>(self) -> Result, D::Error> where [D]: ToOwned> { - let elems: Vec = self.into_owned().into_iter().map(D::try_from).collect::>()?; + fn try_convert_elems>( + self, + ) -> Result, D::Error> + where + [D]: ToOwned>, + { + let elems: Vec = self + .into_owned() + .into_iter() + .map(D::try_from) + .collect::>()?; Ok(TypeRow::from(elems)) } } impl Default for TypeRow -where [T]: ToOwned> { +where + [T]: ToOwned>, +{ fn default() -> Self { Self::new() } } -impl From for TypeRow +impl From for TypeRow where F: Into>, - [T]: ToOwned> + [T]: ToOwned>, { fn from(types: F) -> Self { Self { - types: types.into() + types: types.into(), } } } - -impl Deref for TypeRow where [T]: ToOwned> { +impl Deref for TypeRow +where + [T]: ToOwned>, +{ type Target = [T]; fn deref(&self) -> &Self::Target { @@ -411,7 +442,10 @@ impl Deref for TypeRow where [T]: ToOwned> { } } -impl DerefMut for TypeRow where [T]: ToOwned> { +impl DerefMut for TypeRow +where + [T]: ToOwned>, +{ fn deref_mut(&mut self) -> &mut Self::Target { self.types.to_mut() } From 4c8141aa5fa8fcd42f3ef678b52b35f09a6e25c3 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 10 Jul 2023 13:44:53 +0100 Subject: [PATCH 17/47] T: Clone+'static avoids the crazy [T]: ToOwned> --- src/types.rs | 7 ++--- src/types/simple.rs | 57 ++++++++--------------------------- src/types/simple/serialize.rs | 2 +- 3 files changed, 16 insertions(+), 50 deletions(-) diff --git a/src/types.rs b/src/types.rs index d370edce6..a8e1f8eeb 100644 --- a/src/types.rs +++ b/src/types.rs @@ -329,13 +329,10 @@ impl SignatureDescription { } } - fn row_zip<'a, T: std::fmt::Debug>( + fn row_zip<'a, T: std::fmt::Debug + Clone + 'static>( type_row: &'a TypeRow, name_row: &'a [SmolStr], - ) -> impl Iterator - where - [T]: ToOwned>, - { + ) -> impl Iterator { name_row .iter() .chain(&EmptyStringIterator) diff --git a/src/types/simple.rs b/src/types/simple.rs index 17e677fd0..7b2207197 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -46,7 +46,7 @@ impl Display for SimpleType { } /// Trait of primitive types (SimpleType or ClassicType). -pub trait PrimType: std::fmt::Debug + 'static { +pub trait PrimType: std::fmt::Debug + Clone + 'static { // may be updated with functions in future for necessary shared functionality // across ClassicType and SimpleType // currently used to constrain Container @@ -60,10 +60,7 @@ pub trait PrimType: std::fmt::Debug + 'static { /// For algebraic types Sum, Tuple if one element of type row is linear, the /// overall type is too. #[derive(Clone, Debug, PartialEq, Eq)] -pub enum Container -where - [T]: ToOwned>, -{ +pub enum Container { /// Variable sized list of T. List(Box), /// Hash map from hashable key type to value T. @@ -78,10 +75,7 @@ where Alias(SmolStr), } -impl Display for Container -where - [T]: ToOwned>, -{ +impl Display for Container { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { Container::List(ty) => write!(f, "List({})", ty.as_ref()), @@ -291,18 +285,12 @@ impl<'a> TryFrom<&'a SimpleType> for &'a ClassicType { #[cfg_attr(feature = "pyo3", pyclass)] #[non_exhaustive] #[serde(transparent)] -pub struct TypeRow -where - [T]: ToOwned> + 'static, -{ +pub struct TypeRow { /// The datatypes in the row. types: Cow<'static, [T]>, } -impl Display for TypeRow -where - [T]: ToOwned>, -{ +impl Display for TypeRow { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_char('[')?; display_list(self.types.as_ref(), f)?; @@ -311,10 +299,7 @@ where } #[cfg_attr(feature = "pyo3", pymethods)] -impl TypeRow -where - [T]: ToOwned>, -{ +impl TypeRow { /// Returns the number of types in the row. #[inline(always)] pub fn len(&self) -> usize { @@ -357,10 +342,7 @@ impl TypeRow { } } -impl TypeRow -where - [T]: ToOwned>, -{ +impl TypeRow { /// Create a new empty row. pub const fn new() -> Self { Self { @@ -395,12 +377,9 @@ where self.types.to_mut().get_mut(offset) } - fn try_convert_elems>( + fn try_convert_elems + 'static>( self, - ) -> Result, D::Error> - where - [D]: ToOwned>, - { + ) -> Result, D::Error> { let elems: Vec = self .into_owned() .into_iter() @@ -410,19 +389,15 @@ where } } -impl Default for TypeRow -where - [T]: ToOwned>, -{ +impl Default for TypeRow { fn default() -> Self { Self::new() } } -impl From for TypeRow +impl From for TypeRow where F: Into>, - [T]: ToOwned>, { fn from(types: F) -> Self { Self { @@ -431,10 +406,7 @@ where } } -impl Deref for TypeRow -where - [T]: ToOwned>, -{ +impl Deref for TypeRow { type Target = [T]; fn deref(&self) -> &Self::Target { @@ -442,10 +414,7 @@ where } } -impl DerefMut for TypeRow -where - [T]: ToOwned>, -{ +impl DerefMut for TypeRow { fn deref_mut(&mut self) -> &mut Self::Target { self.types.to_mut() } diff --git a/src/types/simple/serialize.rs b/src/types/simple/serialize.rs index 867bd6285..2cffd53ce 100644 --- a/src/types/simple/serialize.rs +++ b/src/types/simple/serialize.rs @@ -65,7 +65,7 @@ pub(crate) enum SerSimpleType { }, } -impl> From> for SerSimpleType where [T]: ToOwned> { +impl> From> for SerSimpleType { fn from(value: Container) -> Self { match value { Container::Sum(inner) => SerSimpleType::Sum { From a2b4f2c43299a9771cac0c40bb05e23db98acc12 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 10 Jul 2023 13:50:31 +0100 Subject: [PATCH 18/47] Use PrimType constraint for all TypeRow's --- src/types.rs | 4 +++- src/types/simple.rs | 20 +++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/types.rs b/src/types.rs index a8e1f8eeb..96f3a45b9 100644 --- a/src/types.rs +++ b/src/types.rs @@ -19,6 +19,8 @@ use crate::hugr::{Direction, Port}; use crate::utils::display_list; use crate::{resource::ResourceSet, type_row}; +use self::simple::PrimType; + /// The kinds of edges in a HUGR, excluding Hierarchy. //#[cfg_attr(feature = "pyo3", pyclass)] # TODO: Manually derive pyclass with non-unit variants #[derive(Clone, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)] @@ -329,7 +331,7 @@ impl SignatureDescription { } } - fn row_zip<'a, T: std::fmt::Debug + Clone + 'static>( + fn row_zip<'a, T: PrimType>( type_row: &'a TypeRow, name_row: &'a [SmolStr], ) -> impl Iterator { diff --git a/src/types/simple.rs b/src/types/simple.rs index 7b2207197..550fad19d 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -285,12 +285,12 @@ impl<'a> TryFrom<&'a SimpleType> for &'a ClassicType { #[cfg_attr(feature = "pyo3", pyclass)] #[non_exhaustive] #[serde(transparent)] -pub struct TypeRow { +pub struct TypeRow { /// The datatypes in the row. types: Cow<'static, [T]>, } -impl Display for TypeRow { +impl Display for TypeRow { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_char('[')?; display_list(self.types.as_ref(), f)?; @@ -299,7 +299,7 @@ impl Display for TypeRow { } #[cfg_attr(feature = "pyo3", pymethods)] -impl TypeRow { +impl TypeRow { /// Returns the number of types in the row. #[inline(always)] pub fn len(&self) -> usize { @@ -342,7 +342,7 @@ impl TypeRow { } } -impl TypeRow { +impl TypeRow { /// Create a new empty row. pub const fn new() -> Self { Self { @@ -377,9 +377,7 @@ impl TypeRow { self.types.to_mut().get_mut(offset) } - fn try_convert_elems + 'static>( - self, - ) -> Result, D::Error> { + fn try_convert_elems>(self) -> Result, D::Error> { let elems: Vec = self .into_owned() .into_iter() @@ -389,13 +387,13 @@ impl TypeRow { } } -impl Default for TypeRow { +impl Default for TypeRow { fn default() -> Self { Self::new() } } -impl From for TypeRow +impl From for TypeRow where F: Into>, { @@ -406,7 +404,7 @@ where } } -impl Deref for TypeRow { +impl Deref for TypeRow { type Target = [T]; fn deref(&self) -> &Self::Target { @@ -414,7 +412,7 @@ impl Deref for TypeRow { } } -impl DerefMut for TypeRow { +impl DerefMut for TypeRow { fn deref_mut(&mut self) -> &mut Self::Target { self.types.to_mut() } From 8ef83991aae7414a27facd4404265a08cc31574a Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 10 Jul 2023 13:55:07 +0100 Subject: [PATCH 19/47] Revert "TEMP turn off types/simple/serialize.rs" This reverts commit c48e4e709a016e2ef2f7a77a6fd57e555c0a263e. --- src/types/simple.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/types/simple.rs b/src/types/simple.rs index 550fad19d..fe85f0e27 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -21,6 +21,7 @@ use crate::{resource::ResourceSet, type_row}; // // TODO: Compare performance vs flattening this into a single enum #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[serde(from = "serialize::SerSimpleType", into = "serialize::SerSimpleType")] #[non_exhaustive] pub enum SimpleType { /// A type containing only classical data. Elements of this type can be copied. @@ -30,10 +31,11 @@ pub enum SimpleType { /// A linear opaque type that can be downcasted by the extensions that define it. Qpaque(CustomType), /// A nested definition containing other linear types (possibly as well as classical ones) - #[serde(skip)] Qontainer(Container), } +mod serialize; + impl Display for SimpleType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { From d6a74522d249a1226db557d8210a61a88cc92cc8 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 10 Jul 2023 14:30:24 +0100 Subject: [PATCH 20/47] Fix serialization by making SerSimpleType contain only SerSimpleTypes --- src/builder/build_traits.rs | 8 +----- src/macros.rs | 6 ++-- src/types/simple.rs | 10 +++++++ src/types/simple/serialize.rs | 54 +++++++++++++++++++++++++---------- 4 files changed, 53 insertions(+), 25 deletions(-) diff --git a/src/builder/build_traits.rs b/src/builder/build_traits.rs index 19bdd4474..367d93b02 100644 --- a/src/builder/build_traits.rs +++ b/src/builder/build_traits.rs @@ -474,13 +474,7 @@ pub trait Dataflow: Container { values: impl IntoIterator, ) -> Result { let tuple = self.make_tuple(values)?; - let variants = TypeRow::predicate_variants_row(predicate_variants); - let variants = variants - .into_owned() - .into_iter() - .map(SimpleType::Classic) - .collect::>() - .into(); + let variants = TypeRow::predicate_variants_row(predicate_variants).map_into(); let make_op = self.add_dataflow_op(LeafOp::Tag { tag, variants }, vec![tuple])?; Ok(make_op.out_wire(0)) } diff --git a/src/macros.rs b/src/macros.rs index 719369f19..4e9c689a0 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -45,11 +45,11 @@ pub(crate) use impl_box_clone; /// # use hugr::macros::type_row; /// # use hugr::types::{ClassicType, SimpleType, Signature, TypeRow}; /// const B: SimpleType = SimpleType::Classic(ClassicType::bit()); -/// let static_row: TypeRow = type_row![B, B]; -/// let dynamic_row: TypeRow = vec![B, B, B].into(); +/// let static_row: TypeRow = type_row![B, B]; +/// let dynamic_row: TypeRow = vec![B, B, B].into(); /// let sig: Signature = Signature::new_df(static_row.clone(), dynamic_row); /// -/// let repeated_row: TypeRow = type_row![B; 2]; +/// let repeated_row: TypeRow = type_row![B; 2]; /// assert_eq!(repeated_row, static_row); /// ``` #[allow(unused_macros)] diff --git a/src/types/simple.rs b/src/types/simple.rs index fe85f0e27..1ff317ea4 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -387,6 +387,16 @@ impl TypeRow { .collect::>()?; Ok(TypeRow::from(elems)) } + + /// Converts the elements of this TypeRow into some other type that they can `.into()` + pub fn map_into>(self) -> TypeRow { + TypeRow::from( + self.into_owned() + .into_iter() + .map(T2::from) + .collect::>(), + ) + } } impl Default for TypeRow { diff --git a/src/types/simple/serialize.rs b/src/types/simple/serialize.rs index 2cffd53ce..4db36acb8 100644 --- a/src/types/simple/serialize.rs +++ b/src/types/simple/serialize.rs @@ -17,7 +17,7 @@ use super::super::Signature; use crate::ops::constant::HugrIntWidthStore; use crate::resource::ResourceSet; -#[derive(serde::Serialize, serde::Deserialize)] +#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)] #[serde(tag = "t")] pub(crate) enum SerSimpleType { Q, @@ -35,20 +35,20 @@ pub(crate) enum SerSimpleType { l: bool, }, Map { - k: Box, - v: Box, + k: Box, + v: Box, l: bool, }, Tuple { - row: Box>, + row: Box>, l: bool, }, Sum { - row: Box>, + row: Box>, l: bool, }, Array { - inner: Box, + inner: Box, len: usize, l: bool, }, @@ -65,19 +65,27 @@ pub(crate) enum SerSimpleType { }, } -impl> From> for SerSimpleType { +impl PrimType for SerSimpleType { + const LINEAR: bool = true; +} + +impl From> for SerSimpleType +where + SerSimpleType: From, + SimpleType: From, +{ fn from(value: Container) -> Self { match value { Container::Sum(inner) => SerSimpleType::Sum { - row: inner, + row: Box::new(inner.map_into()), l: T::LINEAR, }, Container::List(inner) => SerSimpleType::List { - inner: box_convert(*inner), + inner: Box::new((*inner).into()), l: T::LINEAR, }, Container::Tuple(inner) => SerSimpleType::Tuple { - row: inner, + row: Box::new(inner.map_into()), l: T::LINEAR, }, Container::Map(inner) => SerSimpleType::Map { @@ -158,19 +166,21 @@ impl From for SimpleType { SerSimpleType::Tuple { row: inner, l: true, - } => Container::::Tuple(box_convert_try(*inner)).into(), + } => Container::::Tuple(Box::new(inner.map_into())).into(), SerSimpleType::Tuple { row: inner, l: false, - } => Container::::Tuple(box_convert_try(*inner)).into(), + } => { + Container::::Tuple(Box::new(inner.try_convert_elems().unwrap())).into() + } SerSimpleType::Sum { row: inner, l: true, - } => Container::::Sum(box_convert_try(*inner)).into(), + } => Container::::Sum(Box::new(inner.map_into())).into(), SerSimpleType::Sum { row: inner, l: false, - } => Container::::Sum(box_convert_try(*inner)).into(), + } => Container::::Sum(Box::new(inner.try_convert_elems().unwrap())).into(), SerSimpleType::List { inner, l: true } => { Container::::List(box_convert_try(*inner)).into() } @@ -178,7 +188,8 @@ impl From for SimpleType { Container::::List(box_convert_try(*inner)).into() } SerSimpleType::Map { k, v, l: true } => { - Container::::Map(Box::new(((*k).try_into().unwrap(), *v))).into() + Container::::Map(Box::new(((*k).try_into().unwrap(), (*v).into()))) + .into() } SerSimpleType::Map { k, v, l: false } => Container::::Map(Box::new(( (*k).try_into().unwrap(), @@ -206,3 +217,16 @@ impl From for SimpleType { } } } + +impl TryFrom for ClassicType { + type Error = String; + + fn try_from(value: SerSimpleType) -> Result { + let s: SimpleType = value.into(); + if let SimpleType::Classic(c) = s { + Ok(c) + } else { + Err(format!("Not a ClassicType: {}", s)) + } + } +} From 6c012332022d7675c29fb7c6e773e572e26e327c Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 10 Jul 2023 14:31:15 +0100 Subject: [PATCH 21/47] Drop a now-unnecessary into --- src/ops/dataflow.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ops/dataflow.rs b/src/ops/dataflow.rs index dfffe303e..35ee69ca6 100644 --- a/src/ops/dataflow.rs +++ b/src/ops/dataflow.rs @@ -168,7 +168,7 @@ impl DataflowOpTrait for Call { fn signature(&self) -> Signature { Signature { - static_input: vec![ClassicType::graph_from_sig(self.signature.clone()).into()].into(), + static_input: vec![ClassicType::graph_from_sig(self.signature.clone())].into(), ..self.signature.clone() } } From 9e43ddb0e45bb34843a8a237c56974ca0fb6f639 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 10 Jul 2023 14:35:23 +0100 Subject: [PATCH 22/47] Remove now-unnecessary hoop-jumping in Signature::get for 'other' ports --- src/types.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/types.rs b/src/types.rs index 96f3a45b9..b32b90840 100644 --- a/src/types.rs +++ b/src/types.rs @@ -104,12 +104,11 @@ impl Signature { /// Returns the type of a [`Port`]. Returns `None` if the port is out of bounds. pub fn get(&self, port: Port) -> Option { if port.direction() == Direction::Incoming && port.index() >= self.input.len() { - self.static_input - .get(port.index() - self.input.len())? - .clone() - .try_into() - .ok() - .map(EdgeKind::Static) + Some(EdgeKind::Static( + self.static_input + .get(port.index() - self.input.len())? + .clone(), + )) } else { self.get_df(port).cloned().map(EdgeKind::Value) } From 11ca1e1d98aefbfb7bdbdb7ae6630909c118af62 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Wed, 12 Jul 2023 17:22:15 +0100 Subject: [PATCH 23/47] Drop unused purely_linear methods. (Unused because they shouldn't be, perhaps? Even slightly linear means linear) --- src/types.rs | 6 ------ src/types/simple.rs | 6 ------ 2 files changed, 12 deletions(-) diff --git a/src/types.rs b/src/types.rs index 8a37bb6dc..dcd1e6de3 100644 --- a/src/types.rs +++ b/src/types.rs @@ -69,12 +69,6 @@ impl Signature { self.static_input.is_empty() && self.input.is_empty() && self.output.is_empty() } - /// Returns whether the data wires in the signature are purely linear. - #[inline(always)] - pub fn purely_linear(&self) -> bool { - self.input.purely_linear() && self.output.purely_linear() - } - /// Returns whether the data wires in the signature are purely classical. #[inline(always)] pub fn purely_classical(&self) -> bool { diff --git a/src/types/simple.rs b/src/types/simple.rs index 7bd3ee521..d6e1c1396 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -307,12 +307,6 @@ impl TypeRow { self.types.len() == 0 } - /// Returns whether the row contains only linear data. - #[inline(always)] - pub fn purely_linear(&self) -> bool { - self.types.iter().all(|typ| typ.is_linear()) - } - /// Returns whether the row contains only classic data. #[inline(always)] pub fn purely_classical(&self) -> bool { From 638cd343d4b291b2034381a7dba159e62c063976 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Wed, 12 Jul 2023 17:16:15 +0100 Subject: [PATCH 24/47] PrimType::LINEAR -> CLASSIC --- src/types/simple.rs | 8 ++++---- src/types/simple/serialize.rs | 15 +++++++++------ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/types/simple.rs b/src/types/simple.rs index d6e1c1396..2fb74342c 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -53,8 +53,8 @@ pub trait PrimType { // across ClassicType and SimpleType // currently used to constrain Container - /// Is this type linear? (I.e. does it have any linear components?) - const LINEAR: bool; + /// Is this type classical? (I.e. can it be copied - not if it has *any* linear component) + const CLASSIC: bool; } /// A type that represents a container of other types. @@ -197,11 +197,11 @@ impl Display for ClassicType { } impl PrimType for ClassicType { - const LINEAR: bool = false; + const CLASSIC: bool = true; } impl PrimType for SimpleType { - const LINEAR: bool = true; + const CLASSIC: bool = false; } impl SimpleType { diff --git a/src/types/simple/serialize.rs b/src/types/simple/serialize.rs index 2bb978593..2e3659020 100644 --- a/src/types/simple/serialize.rs +++ b/src/types/simple/serialize.rs @@ -70,27 +70,30 @@ impl> From> for SerSimpleType { match value { Container::Sum(inner) => SerSimpleType::Sum { row: inner, - l: T::LINEAR, + l: !T::CLASSIC, }, Container::List(inner) => SerSimpleType::List { inner: box_convert(*inner), - l: T::LINEAR, + l: !T::CLASSIC, }, Container::Tuple(inner) => SerSimpleType::Tuple { row: inner, - l: T::LINEAR, + l: !T::CLASSIC, }, Container::Map(inner) => SerSimpleType::Map { k: Box::new(inner.0.into()), v: Box::new(inner.1.into()), - l: T::LINEAR, + l: !T::CLASSIC, }, Container::Array(inner, len) => SerSimpleType::Array { inner: box_convert(*inner), len, - l: T::LINEAR, + l: !T::CLASSIC, + }, + Container::Alias(name) => SerSimpleType::Alias { + name, + l: !T::CLASSIC, }, - Container::Alias(name) => SerSimpleType::Alias { name, l: T::LINEAR }, } } } From 267da4e81ee9523771a655a3cd72a2aac875b694 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 14 Jul 2023 10:49:26 +0100 Subject: [PATCH 25/47] Remove LeafOp::linear_count and Signature::linear --- src/ops/leaf.rs | 5 ----- src/types.rs | 17 ----------------- 2 files changed, 22 deletions(-) diff --git a/src/ops/leaf.rs b/src/ops/leaf.rs index 910a460db..0861a7bdf 100644 --- a/src/ops/leaf.rs +++ b/src/ops/leaf.rs @@ -217,11 +217,6 @@ impl OpTrait for LeafOp { } impl LeafOp { - /// Returns the number of linear inputs (also outputs) of the operation. - pub fn linear_count(&self) -> usize { - self.signature().linear().count() - } - /// Returns true if the operation has only classical inputs and outputs. pub fn is_pure_classical(&self) -> bool { self.signature().purely_classical() diff --git a/src/types.rs b/src/types.rs index dcd1e6de3..3bfd3e5d7 100644 --- a/src/types.rs +++ b/src/types.rs @@ -76,23 +76,6 @@ impl Signature { } } impl Signature { - /// Returns the linear part of the signature - /// TODO: This fails when mixing different linear types. - #[inline(always)] - pub fn linear(&self) -> impl Iterator { - debug_assert_eq!( - self.input - .iter() - .filter(|t| t.is_linear()) - .collect::>(), - self.output - .iter() - .filter(|t| t.is_linear()) - .collect::>() - ); - self.input.iter().filter(|t| t.is_linear()) - } - /// Returns the type of a [`Port`]. Returns `None` if the port is out of bounds. pub fn get(&self, port: Port) -> Option { if port.direction() == Direction::Incoming && port.index() >= self.input.len() { From ff854340453da066031d8752b9f361eee0f53696 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 14 Jul 2023 10:53:41 +0100 Subject: [PATCH 26/47] Remove SimpleType::is_linear, keeping only is_classical --- src/builder/build_traits.rs | 4 ++-- src/builder/module_builder.rs | 2 +- src/types.rs | 2 +- src/types/simple.rs | 5 ----- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/builder/build_traits.rs b/src/builder/build_traits.rs index b4899c12f..437e52d2e 100644 --- a/src/builder/build_traits.rs +++ b/src/builder/build_traits.rs @@ -614,7 +614,7 @@ fn wire_up( if let EdgeKind::Value(typ) = base.get_optype(src).port_kind(src_offset).unwrap() { if !local_source { // Non-local value sources require a state edge to an ancestor of dst - if typ.is_linear() { + if !typ.is_classical() { let val_err: ValidationError = InterGraphEdgeError::NonClassicalData { from: src, from_offset: Port::new_outgoing(src_port), @@ -646,7 +646,7 @@ fn wire_up( // TODO: Avoid adding duplicate edges // This should be easy with https://github.com/CQCL-DEV/hugr/issues/130 base.add_other_edge(src, src_sibling)?; - } else if typ.is_linear() && base.linked_ports(src, src_offset).next().is_some() { + } else if !typ.is_classical() && base.linked_ports(src, src_offset).next().is_some() { // Don't copy linear edges. return Err(BuildError::NoCopyLinear(typ)); } diff --git a/src/builder/module_builder.rs b/src/builder/module_builder.rs index fbfb7a30e..3cf0a5750 100644 --- a/src/builder/module_builder.rs +++ b/src/builder/module_builder.rs @@ -132,7 +132,7 @@ impl + AsRef> ModuleBuilder { // Could be fixed by removing single-entry requirement and sorting from // every 0-input node. let name: SmolStr = name.into(); - let linear = typ.is_linear(); + let linear = !typ.is_classical(); let node = self.add_child_op(ops::AliasDefn { name: name.clone(), definition: typ, diff --git a/src/types.rs b/src/types.rs index 3bfd3e5d7..f3eebeac3 100644 --- a/src/types.rs +++ b/src/types.rs @@ -38,7 +38,7 @@ impl EdgeKind { /// Returns whether the type contains only linear data. pub fn is_linear(&self) -> bool { match self { - EdgeKind::Value(t) => t.is_linear(), + EdgeKind::Value(t) => !t.is_classical(), _ => false, } } diff --git a/src/types/simple.rs b/src/types/simple.rs index 2fb74342c..0f1161932 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -205,11 +205,6 @@ impl PrimType for SimpleType { } impl SimpleType { - /// Returns whether the type contains linear data (perhaps as well as classical) - pub fn is_linear(&self) -> bool { - !self.is_classical() - } - /// Returns whether the type contains only classic data. pub fn is_classical(&self) -> bool { matches!(self, Self::Classic(_)) From ea7da61e0e5da55bd7b5bcd92c1b9d82e2b8ad4c Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 14 Jul 2023 11:00:40 +0100 Subject: [PATCH 27/47] Alias{ID,Defn,Decl}: change linear -> classic --- src/builder/module_builder.rs | 12 ++++++------ src/ops/handle.rs | 16 ++++++++++------ src/ops/module.rs | 4 ++-- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/builder/module_builder.rs b/src/builder/module_builder.rs index 3cf0a5750..8c7acb28f 100644 --- a/src/builder/module_builder.rs +++ b/src/builder/module_builder.rs @@ -132,13 +132,13 @@ impl + AsRef> ModuleBuilder { // Could be fixed by removing single-entry requirement and sorting from // every 0-input node. let name: SmolStr = name.into(); - let linear = !typ.is_classical(); + let classical = typ.is_classical(); let node = self.add_child_op(ops::AliasDefn { name: name.clone(), definition: typ, })?; - Ok(AliasID::new(node, name, linear)) + Ok(AliasID::new(node, name, classical)) } /// Add a [`OpType::AliasDecl`] node and return a handle to the Alias. @@ -148,15 +148,15 @@ impl + AsRef> ModuleBuilder { pub fn add_alias_declare( &mut self, name: impl Into, - linear: bool, + classical: bool, ) -> Result, BuildError> { let name: SmolStr = name.into(); let node = self.add_child_op(ops::AliasDecl { name: name.clone(), - linear, + classical, })?; - Ok(AliasID::new(node, name, linear)) + Ok(AliasID::new(node, name, classical)) } } @@ -196,7 +196,7 @@ mod test { let build_result = { let mut module_builder = ModuleBuilder::new(); - let qubit_state_type = module_builder.add_alias_declare("qubit_state", true)?; + let qubit_state_type = module_builder.add_alias_declare("qubit_state", false)?; let f_build = module_builder.define_function( "main", diff --git a/src/ops/handle.rs b/src/ops/handle.rs index 6ad8803b7..7337ef79b 100644 --- a/src/ops/handle.rs +++ b/src/ops/handle.rs @@ -74,21 +74,25 @@ pub struct FuncID(Node); pub struct AliasID { node: Node, name: SmolStr, - linear: bool, + classical: bool, } impl AliasID { /// Construct new AliasID - pub fn new(node: Node, name: SmolStr, linear: bool) -> Self { - Self { node, name, linear } + pub fn new(node: Node, name: SmolStr, classical: bool) -> Self { + Self { + node, + name, + classical, + } } /// Construct new AliasID pub fn get_alias_type(&self) -> SimpleType { - if self.linear { - Container::::Alias(self.name.clone()).into() - } else { + if self.classical { Container::::Alias(self.name.clone()).into() + } else { + Container::::Alias(self.name.clone()).into() } } /// Retrieve the underlying core type diff --git a/src/ops/module.rs b/src/ops/module.rs index 09f794fb9..5c69233a0 100644 --- a/src/ops/module.rs +++ b/src/ops/module.rs @@ -114,8 +114,8 @@ impl OpTrait for AliasDefn { pub struct AliasDecl { /// Alias name pub name: SmolStr, - /// Flag to signify type is linear - pub linear: bool, + /// Flag to signify type is classical + pub classical: bool, } impl_op_name!(AliasDecl); From 972c4ba5c4efd8161cce54bc4352419e69c6055e Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Wed, 12 Jul 2023 17:51:33 +0100 Subject: [PATCH 28/47] EdgeKind.is_linear: clarify comment --- src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types.rs b/src/types.rs index f3eebeac3..32086db8e 100644 --- a/src/types.rs +++ b/src/types.rs @@ -35,7 +35,7 @@ pub enum EdgeKind { } impl EdgeKind { - /// Returns whether the type contains only linear data. + /// Returns whether the type might contain linear data. pub fn is_linear(&self) -> bool { match self { EdgeKind::Value(t) => !t.is_classical(), From 2ee236995b22cd0c325499c7fd1f1ab8e6c81920 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 14 Jul 2023 11:35:11 +0100 Subject: [PATCH 29/47] Some spec updates (esp type constraints TODO) - dropping const-able --- specification/hugr.md | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/specification/hugr.md b/specification/hugr.md index 55d6b5f2e..b354507e5 100644 --- a/specification/hugr.md +++ b/specification/hugr.md @@ -139,8 +139,9 @@ of edge for different relationships. `Value` and `Static` edges are sometimes referred to as _dataflow_ edges. A `Value` edge can carry data of any `SimpleType`: either a `ClassicType` -(ordinary classical data) or a `LinearType` (data which cannot be copied, -including quantum data). A `Static` edge can only carry a `ClassicType`. For +(ordinary classical data, which can be freely copied or discarded) or a +`LinearType` (which cannot - e.g. anything including quantum data). +A `Static` edge can only carry a `ClassicType`. For more details see the [Type System](#type-system) section. As well as the type, dataflow edges are also parametrized by a @@ -1042,7 +1043,7 @@ ClassicType ::= int | Container(ClassicType) LinearType ::= Qubit | QPaque(Name, #) - | Container(LinearType) + | Container(SimpleType) -- Sometimes called 'Qontainer' ``` SimpleTypes are the types of *values* which can be sent down wires, @@ -1065,8 +1066,8 @@ Container types are defined in terms of statically-known element types. Besides `Array`, `Sum` and `Tuple`, these also include variable-sized types: `Graph`, `Map` and `List` (TODO: can we leave those to the Tierkreis resource?). `NewType` -allows named newtypes to be used. Containers are linear if any of their -components are linear. +allows named newtypes to be used. Containers are classic (copyable) only +if all of their components are classic. @@ -1099,7 +1100,7 @@ ports can have any number of connected edges (0 is equivalent to a discard). Our linear types behave like other values passed down a wire. Quantum gates behave just like other nodes on the graph with inputs and outputs, -but there is only one edge leaving or entering each port. In fully +but there is only one edge leaving (or entering) each port. In fully qubit-counted contexts programs take in a number of qubits as input and return the same number, with no discarding. See [quantum resource](#quantum-resource) @@ -1135,20 +1136,12 @@ resource requirements. We will likely also want to add a fixed set of attributes to certain subsets of `TYPE`. In Tierkreis these are called “type constraints”. For example, the `Map` type can only be constructed when the type that we -map from is `Hashable`. For the Hugr, we may need this `Hashable` -constraint, as well as a `Nonlinear` constraint. Finally there may be a -`const-able` or `serializable` constraint meaning that the value can be -put into a `const`-node: this implies the type is `Nonlinear` (but not -vice versa). +map from is `Hashable`. For the Hugr, we will need this `Hashable` +constraint, as well as a `Classic` constraint. -**TODO**: is this set of constraints (nonlinear, const-able, hashable) -fixed? Then Map is in the core HUGR spec. - -Or, can extensions (resources) add new constraints? This is probably too -complex, but then both hashable and Map could be in the Tierkreis -resource. - -(Or, can we do Map without hashable?) +**TODO**: fix this set of constraints (classic/copyable, hashable); +extensions/resources *cannot* add new constraints. Use hashable for +static type parameters, put Map in Tierkreis resource not core spec. ### Resources From f23d301e2bf2ddb8bff2418eb25f2257a926b212 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 14 Jul 2023 12:06:46 +0100 Subject: [PATCH 30/47] Remove LinearType from spec ??? --- specification/hugr.md | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/specification/hugr.md b/specification/hugr.md index b354507e5..52ec3ba1a 100644 --- a/specification/hugr.md +++ b/specification/hugr.md @@ -138,9 +138,9 @@ of edge for different relationships. children. `Value` and `Static` edges are sometimes referred to as _dataflow_ edges. -A `Value` edge can carry data of any `SimpleType`: either a `ClassicType` -(ordinary classical data, which can be freely copied or discarded) or a -`LinearType` (which cannot - e.g. anything including quantum data). +A `Value` edge can carry data of any `SimpleType`: these include the `ClassicType`s +(which can be freely copied or discarded - i.e. ordinary classical data) +as well as anything which cannot - e.g. quantum data. A `Static` edge can only carry a `ClassicType`. For more details see the [Type System](#type-system) section. @@ -156,9 +156,9 @@ As well as the type, dataflow edges are also parametrized by a [Non-local Edges](#non-local-edges) -``` -SimpleType ::= ClassicType | LinearType +`SimpleType` $\supset$ `ClassicType` +``` EdgeKind ::= Hierarchy | Value(Locality, SimpleType) | Static(Local | Ext, ClassicType) | Order | ControlFlow Locality ::= Local | Ext | Dom @@ -176,7 +176,7 @@ edges, with `Static` edges following `Value` edges in the ordering. Note that the locality is not fixed or even specified by the signature. A source port with a `ClassicType` may have any number of edges associated with -it (including zero, which means "discard"). A port with a `LinearType`, and a target port of any type, +it (including zero, which means "discard"). Any other port must have exactly one edge associated with it. This captures the property of linear types that the value is used exactly once. See [Linearity](#linearity). @@ -1022,12 +1022,11 @@ A grammar of available types is defined below. ```haskell Type ::= [Resources]SimpleType -- Rows are ordered lists, not sets -# ::= #(LinearType), #(ClassicType) +# ::= #(SimpleType) #(T) ::= (T)* Resources ::= (Resource)* -- set not list -SimpleType ::= ClassicType | LinearType Container(T) ::= List(T) | Tuple(#(T)) | Array(T) @@ -1041,9 +1040,10 @@ ClassicType ::= int | Graph[R](#, #) | Opaque(Name, #) | Container(ClassicType) -LinearType ::= Qubit +SimpleType ::= Qubit | QPaque(Name, #) | Container(SimpleType) -- Sometimes called 'Qontainer' + | ClassicType ``` SimpleTypes are the types of *values* which can be sent down wires, @@ -1093,18 +1093,19 @@ i.e. this does not affect behaviour of the HUGR. Row types are used ### Linearity For expressing and rewriting quantum programs we draw a distinction between -`ClassicType` and `LinearType`, the latter being values which must be used +arbitrary `SimpleType`s and the subset of `ClassicType`s. Only `ClassicType`s +may be used more than once or discarded; the former must always be used exactly once. This leads to a constraint on the HUGR that outgoing ports -of `LinearType` must have exactly one edge leaving them. `ClassicType` outgoing -ports can have any number of connected edges (0 is equivalent to a discard). - -Our linear types behave like other values passed down a wire. Quantum -gates behave just like other nodes on the graph with inputs and outputs, -but there is only one edge leaving (or entering) each port. In fully -qubit-counted contexts programs take in a number of qubits as input and -return the same number, with no discarding. See -[quantum resource](#quantum-resource) -for more. +must have exactly one edge leaving them unless they are `ClassicType`, where +outgoing ports may have anynum number of connected edges (0 is equivalent +to a discard). All incoming ports must have exactly one edge connected to them. + +# Our linear types behave like other values passed down a wire. +# Quantum gates behave just like other nodes on the graph with +# inputs and outputs, but there is only one edge leaving (or entering) each port. +In fully qubit-counted contexts programs take in a number of qubits +as input and return the same number, with no discarding. See +[quantum resource](#quantum-resource) for more. ### Resources From 21a8fd9c9d7064b929233322de328e3913866514 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 14 Jul 2023 12:21:40 +0100 Subject: [PATCH 31/47] Comment out pyo3 of TypeRow w/TODO; fix doc link --- src/macros.rs | 2 +- src/types/simple.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index 4e9c689a0..11e592ea7 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -80,7 +80,7 @@ macro_rules! type_row { /// Like [type_row!] but for rows of [ClassicType]s /// -/// [ClassicType]: types::ClassicType +/// [ClassicType]: crate::types::ClassicType #[allow(unused_macros)] #[macro_export] macro_rules! classic_row { diff --git a/src/types/simple.rs b/src/types/simple.rs index 1ff317ea4..a422ba5b0 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -284,7 +284,7 @@ impl<'a> TryFrom<&'a SimpleType> for &'a ClassicType { /// List of types, used for function signatures. #[derive(Clone, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)] -#[cfg_attr(feature = "pyo3", pyclass)] +//#[cfg_attr(feature = "pyo3", pyclass)] // TODO: expose unparameterized versions #[non_exhaustive] #[serde(transparent)] pub struct TypeRow { @@ -300,7 +300,7 @@ impl Display for TypeRow { } } -#[cfg_attr(feature = "pyo3", pymethods)] +//#[cfg_attr(feature = "pyo3", pymethods)] // TODO: expose unparameterized versions impl TypeRow { /// Returns the number of types in the row. #[inline(always)] From 48e4e39ac74c389c6885afa9831c8addd02030e5 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 17 Jul 2023 12:06:04 +0100 Subject: [PATCH 32/47] Use unicode superset --- specification/hugr.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specification/hugr.md b/specification/hugr.md index 52ec3ba1a..1a5369d92 100644 --- a/specification/hugr.md +++ b/specification/hugr.md @@ -156,9 +156,9 @@ As well as the type, dataflow edges are also parametrized by a [Non-local Edges](#non-local-edges) -`SimpleType` $\supset$ `ClassicType` - ``` +SimpleType ⊃ ClassicType -- In the absence of unicode: "SimpleType is a superset of ClassicType" + EdgeKind ::= Hierarchy | Value(Locality, SimpleType) | Static(Local | Ext, ClassicType) | Order | ControlFlow Locality ::= Local | Ext | Dom From 230adf48a7815458a4076ffc38fd67612e855e59 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 17 Jul 2023 12:09:17 +0100 Subject: [PATCH 33/47] typo: anynum -> any --- specification/hugr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/hugr.md b/specification/hugr.md index 1a5369d92..5d8d26c2a 100644 --- a/specification/hugr.md +++ b/specification/hugr.md @@ -1097,7 +1097,7 @@ arbitrary `SimpleType`s and the subset of `ClassicType`s. Only `ClassicType`s may be used more than once or discarded; the former must always be used exactly once. This leads to a constraint on the HUGR that outgoing ports must have exactly one edge leaving them unless they are `ClassicType`, where -outgoing ports may have anynum number of connected edges (0 is equivalent +outgoing ports may have any number of connected edges (0 is equivalent to a discard). All incoming ports must have exactly one edge connected to them. # Our linear types behave like other values passed down a wire. From 5e90a5c9baeaf415ddfc8380f677d6410b47bc5c Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 17 Jul 2023 14:30:37 +0100 Subject: [PATCH 34/47] Use classic_row! --- src/hugr/typecheck.rs | 6 +++--- src/ops/constant.rs | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/hugr/typecheck.rs b/src/hugr/typecheck.rs index cdfde2b5a..b6c343956 100644 --- a/src/hugr/typecheck.rs +++ b/src/hugr/typecheck.rs @@ -145,7 +145,7 @@ pub fn typecheck_const(typ: &ClassicType, val: &ConstValue) -> Result<(), ConstT mod test { use cool_asserts::assert_matches; - use crate::types::ClassicType; + use crate::{classic_row, types::ClassicType}; use super::*; @@ -162,10 +162,10 @@ mod test { typecheck_const(&ClassicType::F64, &ConstValue::i64(5)), Err(ConstTypeError::Failed(ClassicType::F64)) ); - let tuple_ty = ClassicType::Container(Container::Tuple(Box::new(TypeRow::from(vec![ + let tuple_ty = ClassicType::Container(Container::Tuple(Box::new(classic_row![ INT, ClassicType::F64, - ])))); + ]))); typecheck_const( &tuple_ty, &ConstValue::Tuple(vec![ConstValue::i64(7), ConstValue::F64(5.1)]), diff --git a/src/ops/constant.rs b/src/ops/constant.rs index 0907eb934..dcc5d1f68 100644 --- a/src/ops/constant.rs +++ b/src/ops/constant.rs @@ -236,6 +236,7 @@ mod test { use super::ConstValue; use crate::{ builder::{BuildError, Container, DFGBuilder, Dataflow, DataflowHugr}, + classic_row, hugr::{typecheck::ConstTypeError, ValidationError}, type_row, types::{ClassicType, SimpleType, TypeRow}, @@ -244,7 +245,7 @@ mod test { #[test] fn test_predicate() -> Result<(), BuildError> { let pred_rows = vec![ - TypeRow::from(vec![ClassicType::i64(), ClassicType::F64]), + classic_row![ClassicType::i64(), ClassicType::F64], type_row![], ]; let pred_ty = SimpleType::new_predicate(pred_rows.clone()); @@ -273,7 +274,7 @@ mod test { #[test] fn test_bad_predicate() { let pred_rows = vec![ - TypeRow::from(vec![ClassicType::i64(), ClassicType::F64]), + classic_row![ClassicType::i64(), ClassicType::F64], type_row![], ]; let pred_ty = SimpleType::new_predicate(pred_rows.clone()); From 3a6ec73d717c1ed9f9819ae0acf8456a7770948c Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 17 Jul 2023 14:44:55 +0100 Subject: [PATCH 35/47] SerializableType trait w/CLASSIC, unimplemented for SerSimpleType --- src/types/simple.rs | 11 ++--------- src/types/simple/serialize.rs | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/types/simple.rs b/src/types/simple.rs index f28f12907..20b040a01 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -52,9 +52,6 @@ pub trait PrimType: std::fmt::Debug + Clone + 'static { // may be updated with functions in future for necessary shared functionality // across ClassicType and SimpleType // currently used to constrain Container - - /// Is this type classical? (I.e. can it be copied - not if it has *any* linear component) - const CLASSIC: bool; } /// A type that represents a container of other types. @@ -201,13 +198,9 @@ impl Display for ClassicType { } } -impl PrimType for ClassicType { - const CLASSIC: bool = true; -} +impl PrimType for ClassicType {} -impl PrimType for SimpleType { - const CLASSIC: bool = false; -} +impl PrimType for SimpleType {} impl SimpleType { /// Returns whether the type contains only classic data. diff --git a/src/types/simple/serialize.rs b/src/types/simple/serialize.rs index 968780663..a40eca7e4 100644 --- a/src/types/simple/serialize.rs +++ b/src/types/simple/serialize.rs @@ -65,11 +65,21 @@ pub(crate) enum SerSimpleType { }, } -impl PrimType for SerSimpleType { +impl PrimType for SerSimpleType {} + +trait SerializableType: PrimType { + const CLASSIC: bool; +} + +impl SerializableType for ClassicType { + const CLASSIC: bool = true; +} + +impl SerializableType for SimpleType { const CLASSIC: bool = false; } -impl From> for SerSimpleType +impl From> for SerSimpleType where SerSimpleType: From, SimpleType: From, From 3061a5fea1eba0805bafe2ad53475b6d063dfea3 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 17 Jul 2023 15:27:08 +0100 Subject: [PATCH 36/47] A couple more classic_row!s --- src/ops/constant.rs | 8 ++++++-- src/types/simple.rs | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ops/constant.rs b/src/ops/constant.rs index dcc5d1f68..1745580f1 100644 --- a/src/ops/constant.rs +++ b/src/ops/constant.rs @@ -3,8 +3,8 @@ use std::any::Any; use crate::{ + classic_row, macros::impl_box_clone, - type_row, types::{ClassicType, Container, EdgeKind, SimpleType, TypeRow}, }; @@ -171,7 +171,11 @@ impl ConstValue { /// Constant Sum over units, used as predicates. pub fn simple_predicate(tag: usize, size: usize) -> Self { - Self::predicate(tag, Self::unit(), std::iter::repeat(type_row![]).take(size)) + Self::predicate( + tag, + Self::unit(), + std::iter::repeat(classic_row![]).take(size), + ) } /// Constant Sum over Tuples, used as predicates. diff --git a/src/types/simple.rs b/src/types/simple.rs index 20b040a01..4db299a55 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -12,8 +12,8 @@ use pyo3::prelude::*; use smol_str::SmolStr; use super::{custom::CustomType, Signature}; -use crate::{ops::constant::HugrIntWidthStore, utils::display_list}; -use crate::{resource::ResourceSet, type_row}; +use crate::resource::ResourceSet; +use crate::{classic_row, ops::constant::HugrIntWidthStore, utils::display_list}; /// A type that represents concrete data. Can include both linear and classical parts. /// @@ -167,7 +167,7 @@ impl ClassicType { /// New simple predicate with empty Tuple variants pub fn new_simple_predicate(size: usize) -> Self { - Self::new_predicate(std::iter::repeat(type_row![]).take(size)) + Self::new_predicate(std::iter::repeat(classic_row![]).take(size)) } } From fdf88bacdffb86553825760c6011620659054db4 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 17 Jul 2023 15:28:45 +0100 Subject: [PATCH 37/47] Drop some unnecessary type annotations (add comments) --- src/types/simple.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/types/simple.rs b/src/types/simple.rs index 4db299a55..be20bb85c 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -212,7 +212,8 @@ impl SimpleType { pub fn new_sum(row: impl Into>) -> Self { let row = row.into(); if row.purely_classical() { - let row: TypeRow = row.try_convert_elems().unwrap(); + // This should succeed given purely_classical has returned True + let row = row.try_convert_elems().unwrap(); Container::::Sum(Box::new(row)).into() } else { Container::::Sum(Box::new(row)).into() @@ -223,7 +224,8 @@ impl SimpleType { pub fn new_tuple(row: impl Into>) -> Self { let row = row.into(); if row.purely_classical() { - let row: TypeRow = row.try_convert_elems().unwrap(); + // This should succeed given purely_classical has returned True + let row = row.try_convert_elems().unwrap(); Container::::Tuple(Box::new(row)).into() } else { Container::::Tuple(Box::new(row)).into() From 9a11e07bd9cab7f35178b16ddf8a1bd00688f2e4 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 17 Jul 2023 15:30:28 +0100 Subject: [PATCH 38/47] SimpleRow + ClassicRow --- src/builder/build_traits.rs | 20 +++++++-------- src/builder/cfg.rs | 51 +++++++++++++++++++------------------ src/builder/conditional.rs | 12 ++++----- src/builder/dataflow.rs | 6 ++--- src/builder/tail_loop.rs | 12 ++++----- src/extensions/rotation.rs | 5 ++-- src/hugr/typecheck.rs | 4 +-- src/macros.rs | 18 ++++++------- src/ops/constant.rs | 16 ++++++------ src/ops/controlflow.rs | 44 ++++++++++++++++---------------- src/ops/dataflow.rs | 18 ++++++------- src/ops/leaf.rs | 10 ++++---- src/ops/validate.rs | 15 +++++------ src/resource.rs | 14 +++------- src/types.rs | 23 ++++++++--------- src/types/simple.rs | 16 +++++++----- 16 files changed, 139 insertions(+), 145 deletions(-) diff --git a/src/builder/build_traits.rs b/src/builder/build_traits.rs index 06c232d17..a76c6214c 100644 --- a/src/builder/build_traits.rs +++ b/src/builder/build_traits.rs @@ -16,7 +16,7 @@ use crate::{ types::EdgeKind, }; -use crate::types::{ClassicType, Signature, SimpleType, TypeRow}; +use crate::types::{ClassicRow, ClassicType, Signature, SimpleRow, SimpleType}; use itertools::Itertools; @@ -277,11 +277,11 @@ pub trait Dataflow: Container { fn cfg_builder( &mut self, inputs: impl IntoIterator, - output_types: TypeRow, + output_types: SimpleRow, ) -> Result, BuildError> { let (input_types, input_wires): (Vec, Vec) = inputs.into_iter().unzip(); - let inputs: TypeRow = input_types.into(); + let inputs: SimpleRow = input_types.into(); let (cfg_node, _) = add_op_with_wires( self, @@ -336,7 +336,7 @@ pub trait Dataflow: Container { &mut self, just_inputs: impl IntoIterator, inputs_outputs: impl IntoIterator, - just_out_types: TypeRow, + just_out_types: ClassicRow, ) -> Result, BuildError> { let (input_types, mut input_wires): (Vec, Vec) = just_inputs.into_iter().unzip(); @@ -368,16 +368,16 @@ pub trait Dataflow: Container { /// the Conditional node. fn conditional_builder( &mut self, - (predicate_inputs, predicate_wire): (impl IntoIterator>, Wire), + (predicate_inputs, predicate_wire): (impl IntoIterator, Wire), other_inputs: impl IntoIterator, - output_types: TypeRow, + output_types: SimpleRow, ) -> Result, BuildError> { let mut input_wires = vec![predicate_wire]; let (input_types, rest_input_wires): (Vec, Vec) = other_inputs.into_iter().unzip(); input_wires.extend(rest_input_wires); - let inputs: TypeRow = input_types.into(); + let inputs: SimpleRow = input_types.into(); let predicate_inputs: Vec<_> = predicate_inputs.into_iter().collect(); let n_cases = predicate_inputs.len(); let n_out_wires = output_types.len(); @@ -452,7 +452,7 @@ pub trait Dataflow: Container { fn make_tag( &mut self, tag: usize, - variants: impl Into>, + variants: impl Into, value: Wire, ) -> Result { let make_op = self.add_dataflow_op( @@ -470,11 +470,11 @@ pub trait Dataflow: Container { fn make_predicate( &mut self, tag: usize, - predicate_variants: impl IntoIterator>, + predicate_variants: impl IntoIterator, values: impl IntoIterator, ) -> Result { let tuple = self.make_tuple(values)?; - let variants = TypeRow::predicate_variants_row(predicate_variants).map_into(); + let variants = ClassicRow::predicate_variants_row(predicate_variants).map_into(); let make_op = self.add_dataflow_op(LeafOp::Tag { tag, variants }, vec![tuple])?; Ok(make_op.out_wire(0)) } diff --git a/src/builder/cfg.rs b/src/builder/cfg.rs index 1ebd4ddc4..425460d57 100644 --- a/src/builder/cfg.rs +++ b/src/builder/cfg.rs @@ -10,7 +10,7 @@ use super::{ use crate::{ hugr::view::HugrView, type_row, - types::{ClassicType, SimpleType}, + types::{ClassicRow, SimpleRow, SimpleType}, }; use crate::ops::handle::NodeHandle; @@ -18,7 +18,7 @@ use crate::ops::{self, BasicBlock, OpType}; use crate::types::Signature; use crate::Node; -use crate::{hugr::HugrMut, types::TypeRow, Hugr}; +use crate::{hugr::HugrMut, Hugr}; /// Builder for a [`crate::ops::CFG`] child control /// flow graph @@ -26,7 +26,7 @@ use crate::{hugr::HugrMut, types::TypeRow, Hugr}; pub struct CFGBuilder { pub(super) base: T, pub(super) cfg_node: Node, - pub(super) inputs: Option>, + pub(super) inputs: Option, pub(super) exit_node: Node, pub(super) n_out_wires: usize, } @@ -59,8 +59,8 @@ impl + AsRef> SubContainer for CFGBuilder { impl CFGBuilder { /// New CFG rooted HUGR builder pub fn new( - input: impl Into>, - output: impl Into>, + input: impl Into, + output: impl Into, ) -> Result { let input = input.into(); let output = output.into(); @@ -86,8 +86,8 @@ impl + AsRef> CFGBuilder { pub(super) fn create( mut base: B, cfg_node: Node, - input: TypeRow, - output: TypeRow, + input: SimpleRow, + output: SimpleRow, ) -> Result { let n_out_wires = output.len(); let exit_block_type = OpType::BasicBlock(BasicBlock::Exit { @@ -129,18 +129,18 @@ impl + AsRef> CFGBuilder { /// This function will return an error if there is an error adding the node. pub fn block_builder( &mut self, - inputs: TypeRow, - predicate_variants: Vec>, - other_outputs: TypeRow, + inputs: SimpleRow, + predicate_variants: Vec, + other_outputs: SimpleRow, ) -> Result, BuildError> { self.any_block_builder(inputs, predicate_variants, other_outputs, false) } fn any_block_builder( &mut self, - inputs: TypeRow, - predicate_variants: Vec>, - other_outputs: TypeRow, + inputs: SimpleRow, + predicate_variants: Vec, + other_outputs: SimpleRow, entry: bool, ) -> Result, BuildError> { let op = OpType::BasicBlock(BasicBlock::DFB { @@ -173,8 +173,8 @@ impl + AsRef> CFGBuilder { /// This function will return an error if there is an error adding the node. pub fn simple_block_builder( &mut self, - inputs: TypeRow, - outputs: TypeRow, + inputs: SimpleRow, + outputs: SimpleRow, n_cases: usize, ) -> Result, BuildError> { self.block_builder(inputs, vec![type_row![]; n_cases], outputs) @@ -189,8 +189,8 @@ impl + AsRef> CFGBuilder { /// This function will return an error if an entry block has already been built. pub fn entry_builder( &mut self, - predicate_variants: Vec>, - other_outputs: TypeRow, + predicate_variants: Vec, + other_outputs: SimpleRow, ) -> Result, BuildError> { let inputs = self .inputs @@ -207,7 +207,7 @@ impl + AsRef> CFGBuilder { /// This function will return an error if there is an error adding the node. pub fn simple_entry_builder( &mut self, - outputs: TypeRow, + outputs: SimpleRow, n_cases: usize, ) -> Result, BuildError> { self.entry_builder(vec![type_row![]; n_cases], outputs) @@ -251,15 +251,15 @@ impl + AsRef> BlockBuilder { fn create( base: B, block_n: Node, - predicate_variants: Vec>, - other_outputs: TypeRow, - inputs: TypeRow, + predicate_variants: Vec, + other_outputs: SimpleRow, + inputs: SimpleRow, ) -> Result { // The node outputs a predicate before the data outputs of the block node let predicate_type = SimpleType::new_predicate(predicate_variants); let mut node_outputs = vec![predicate_type]; node_outputs.extend_from_slice(&other_outputs); - let signature = Signature::new_df(inputs, TypeRow::from(node_outputs)); + let signature = Signature::new_df(inputs, SimpleRow::from(node_outputs)); let db = DFGBuilder::create_with_io(base, block_n, signature)?; Ok(BlockBuilder::from_dfg_builder(db)) } @@ -282,9 +282,9 @@ impl + AsRef> BlockBuilder { impl BlockBuilder { /// Initialize a [`BasicBlock::DFB`] rooted HUGR builder pub fn new( - inputs: impl Into>, - predicate_variants: impl IntoIterator>, - other_outputs: impl Into>, + inputs: impl Into, + predicate_variants: impl IntoIterator, + other_outputs: impl Into, ) -> Result { let inputs = inputs.into(); let predicate_variants: Vec<_> = predicate_variants.into_iter().collect(); @@ -308,6 +308,7 @@ mod test { use crate::builder::build_traits::HugrBuilder; use crate::builder::{DataflowSubContainer, ModuleBuilder}; use crate::macros::classic_row; + use crate::types::ClassicType; use crate::{builder::test::NAT, ops::ConstValue, type_row, types::Signature}; use cool_asserts::assert_matches; diff --git a/src/builder/conditional.rs b/src/builder/conditional.rs index eb2f54c78..f57c3c3cb 100644 --- a/src/builder/conditional.rs +++ b/src/builder/conditional.rs @@ -1,5 +1,5 @@ use crate::hugr::view::HugrView; -use crate::types::{ClassicType, Signature, SimpleType, TypeRow}; +use crate::types::{ClassicRow, Signature, SimpleRow}; use crate::ops; use crate::ops::handle::CaseID; @@ -146,9 +146,9 @@ impl HugrBuilder for ConditionalBuilder { impl ConditionalBuilder { /// Initialize a Conditional rooted HUGR builder pub fn new( - predicate_inputs: impl IntoIterator>, - other_inputs: impl Into>, - outputs: impl Into>, + predicate_inputs: impl IntoIterator, + other_inputs: impl Into, + outputs: impl Into, ) -> Result { let predicate_inputs: Vec<_> = predicate_inputs.into_iter().collect(); let other_inputs = other_inputs.into(); @@ -177,8 +177,8 @@ impl ConditionalBuilder { impl CaseBuilder { /// Initialize a Case rooted HUGR pub fn new( - input: impl Into>, - output: impl Into>, + input: impl Into, + output: impl Into, ) -> Result { let input = input.into(); let output = output.into(); diff --git a/src/builder/dataflow.rs b/src/builder/dataflow.rs index 94cafa661..421c3842a 100644 --- a/src/builder/dataflow.rs +++ b/src/builder/dataflow.rs @@ -7,7 +7,7 @@ use std::marker::PhantomData; use crate::hugr::{HugrView, ValidationError}; use crate::ops; -use crate::types::{Signature, SimpleType, TypeRow}; +use crate::types::{Signature, SimpleRow}; use crate::Node; use crate::{hugr::HugrMut, Hugr}; @@ -60,8 +60,8 @@ impl DFGBuilder { /// /// Error in adding DFG child nodes. pub fn new( - input: impl Into>, - output: impl Into>, + input: impl Into, + output: impl Into, ) -> Result, BuildError> { let input = input.into(); let output = output.into(); diff --git a/src/builder/tail_loop.rs b/src/builder/tail_loop.rs index 30485b662..58a846265 100644 --- a/src/builder/tail_loop.rs +++ b/src/builder/tail_loop.rs @@ -1,7 +1,7 @@ use crate::ops::{self, OpType}; use crate::hugr::view::HugrView; -use crate::types::{ClassicType, Signature, SimpleType, TypeRow}; +use crate::types::{ClassicRow, Signature, SimpleRow}; use crate::{Hugr, Node}; use super::build_traits::SubContainer; @@ -49,7 +49,7 @@ impl + AsRef> TailLoopBuilder { } /// The output types of the child graph, including the predicate as the first. - pub fn internal_output_row(&self) -> Result, BuildError> { + pub fn internal_output_row(&self) -> Result { self.loop_signature().map(ops::TailLoop::body_output_row) } } @@ -72,9 +72,9 @@ impl + AsRef> TailLoopBuilder { impl TailLoopBuilder { /// Initialize new builder for a [`ops::TailLoop`] rooted HUGR pub fn new( - just_inputs: impl Into>, - inputs_outputs: impl Into>, - just_outputs: impl Into>, + just_inputs: impl Into, + inputs_outputs: impl Into, + just_outputs: impl Into, ) -> Result { let tail_loop = ops::TailLoop { just_inputs: just_inputs.into(), @@ -100,7 +100,7 @@ mod test { hugr::ValidationError, ops::ConstValue, type_row, - types::Signature, + types::{ClassicType, Signature}, Hugr, }; diff --git a/src/extensions/rotation.rs b/src/extensions/rotation.rs index 119b27f8d..03e65833e 100644 --- a/src/extensions/rotation.rs +++ b/src/extensions/rotation.rs @@ -14,7 +14,7 @@ use pyo3::prelude::*; use crate::ops::constant::CustomConst; use crate::resource::{OpDef, ResourceSet, TypeDef}; use crate::types::type_param::TypeArg; -use crate::types::{ClassicType, CustomType, SimpleType, TypeRow}; +use crate::types::{ClassicType, CustomType, SimpleRow, SimpleType}; use crate::Resource; pub const fn resource_id() -> SmolStr { @@ -34,8 +34,7 @@ pub fn resource() -> Resource { vec![], HashMap::default(), |_arg_values: &[TypeArg]| { - let t: TypeRow = - vec![SimpleType::Classic(Type::Angle.custom_type().into())].into(); + let t: SimpleRow = vec![SimpleType::Classic(Type::Angle.custom_type().into())].into(); Ok((t.clone(), t, ResourceSet::default())) }, ); diff --git a/src/hugr/typecheck.rs b/src/hugr/typecheck.rs index b6c343956..c7f44ea86 100644 --- a/src/hugr/typecheck.rs +++ b/src/hugr/typecheck.rs @@ -6,10 +6,10 @@ use lazy_static::lazy_static; use std::collections::HashSet; use crate::hugr::*; -use crate::types::TypeRow; // For static typechecking use crate::ops::ConstValue; +use crate::types::simple::ClassicRow; use crate::types::{ClassicType, Container}; use crate::ops::constant::{HugrIntValueStore, HugrIntWidthStore, HUGR_MAX_INT_WIDTH}; @@ -53,7 +53,7 @@ pub enum ConstTypeError { /// A mismatch between the embedded type and the type we're checking /// against, as above, but for rows instead of simple types #[error("Type mismatch for const - expected {0}, found {1}")] - TypeRowMismatch(TypeRow, TypeRow), + TypeRowMismatch(ClassicRow, ClassicRow), } lazy_static! { diff --git a/src/macros.rs b/src/macros.rs index 11e592ea7..690e73cc1 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -43,13 +43,13 @@ pub(crate) use impl_box_clone; /// Example: /// ``` /// # use hugr::macros::type_row; -/// # use hugr::types::{ClassicType, SimpleType, Signature, TypeRow}; +/// # use hugr::types::{ClassicType, SimpleType, Signature, SimpleRow}; /// const B: SimpleType = SimpleType::Classic(ClassicType::bit()); -/// let static_row: TypeRow = type_row![B, B]; -/// let dynamic_row: TypeRow = vec![B, B, B].into(); +/// let static_row: SimpleRow = type_row![B, B]; +/// let dynamic_row: SimpleRow = vec![B, B, B].into(); /// let sig: Signature = Signature::new_df(static_row.clone(), dynamic_row); /// -/// let repeated_row: TypeRow = type_row![B; 2]; +/// let repeated_row: SimpleRow = type_row![B; 2]; /// assert_eq!(repeated_row, static_row); /// ``` #[allow(unused_macros)] @@ -57,14 +57,14 @@ pub(crate) use impl_box_clone; macro_rules! type_row { () => { { - $crate::types::TypeRow::new() + $crate::types::simple::TypeRow::new() } }; ($($t:expr),+ $(,)?) => { { use $crate::types; static ROW: &[types::SimpleType] = &[$($t),*]; - let row: types::TypeRow<_> = ROW.into(); + let row: types::SimpleRow = ROW.into(); row } }; @@ -72,7 +72,7 @@ macro_rules! type_row { { use $crate::types; static ROW: &[types::SimpleType] = &[$t; $n]; - let row: types::TypeRow<_> = ROW.into(); + let row: types::SimpleRow = ROW.into(); row } }; @@ -86,14 +86,14 @@ macro_rules! type_row { macro_rules! classic_row { () => { { - $crate::types::TypeRow::new() + $crate::types::ClassicRow::new() } }; ($($t:expr),+ $(,)?) => { { use $crate::types; static ROW: &[types::ClassicType] = &[$($t),*]; - let row: types::TypeRow<_> = ROW.into(); + let row: types::ClassicRow = ROW.into(); row } }; diff --git a/src/ops/constant.rs b/src/ops/constant.rs index 1745580f1..f1dbdb1bb 100644 --- a/src/ops/constant.rs +++ b/src/ops/constant.rs @@ -5,7 +5,7 @@ use std::any::Any; use crate::{ classic_row, macros::impl_box_clone, - types::{ClassicType, Container, EdgeKind, SimpleType, TypeRow}, + types::{ClassicRow, ClassicType, Container, EdgeKind, SimpleType}, }; use downcast_rs::{impl_downcast, Downcast}; @@ -64,7 +64,7 @@ pub enum ConstValue { tag: usize, // We require the type to be entirely Classic (i.e. we don't allow // a classic variant of a Sum with other variants that are linear) - variants: TypeRow, + variants: ClassicRow, val: Box, }, /// A tuple of constant values. @@ -182,11 +182,11 @@ impl ConstValue { pub fn predicate( tag: usize, val: ConstValue, - variant_rows: impl IntoIterator>, + variant_rows: impl IntoIterator, ) -> Self { ConstValue::Sum { tag, - variants: TypeRow::predicate_variants_row(variant_rows), + variants: ClassicRow::predicate_variants_row(variant_rows), val: Box::new(val), } } @@ -243,7 +243,7 @@ mod test { classic_row, hugr::{typecheck::ConstTypeError, ValidationError}, type_row, - types::{ClassicType, SimpleType, TypeRow}, + types::{ClassicType, SimpleRow, SimpleType}, }; #[test] @@ -254,7 +254,7 @@ mod test { ]; let pred_ty = SimpleType::new_predicate(pred_rows.clone()); - let mut b = DFGBuilder::new(type_row![], TypeRow::from(vec![pred_ty.clone()]))?; + let mut b = DFGBuilder::new(type_row![], SimpleRow::from(vec![pred_ty.clone()]))?; let c = b.add_constant(ConstValue::predicate( 0, ConstValue::Tuple(vec![ConstValue::i64(3), ConstValue::F64(3.15)]), @@ -263,7 +263,7 @@ mod test { let w = b.load_const(&c)?; b.finish_hugr_with_outputs([w]).unwrap(); - let mut b = DFGBuilder::new(type_row![], TypeRow::from(vec![pred_ty]))?; + let mut b = DFGBuilder::new(type_row![], SimpleRow::from(vec![pred_ty]))?; let c = b.add_constant(ConstValue::predicate( 1, ConstValue::Tuple(vec![]), @@ -283,7 +283,7 @@ mod test { ]; let pred_ty = SimpleType::new_predicate(pred_rows.clone()); - let mut b = DFGBuilder::new(type_row![], TypeRow::from(vec![pred_ty])).unwrap(); + let mut b = DFGBuilder::new(type_row![], SimpleRow::from(vec![pred_ty])).unwrap(); let c = b .add_constant(ConstValue::predicate( 0, diff --git a/src/ops/controlflow.rs b/src/ops/controlflow.rs index 9bc9358c7..6b80b3e87 100644 --- a/src/ops/controlflow.rs +++ b/src/ops/controlflow.rs @@ -2,7 +2,7 @@ use smol_str::SmolStr; -use crate::types::{ClassicType, EdgeKind, Signature, SimpleType, TypeRow}; +use crate::types::{ClassicRow, EdgeKind, Signature, SimpleRow, SimpleType}; use super::dataflow::DataflowOpTrait; use super::OpTag; @@ -12,11 +12,11 @@ use super::{impl_op_name, OpName, OpTrait, StaticTag}; #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct TailLoop { /// Types that are only input - pub just_inputs: TypeRow, + pub just_inputs: ClassicRow, /// Types that are only output - pub just_outputs: TypeRow, + pub just_outputs: ClassicRow, /// Types that are appended to both input and output - pub rest: TypeRow, + pub rest: SimpleRow, } impl_op_name!(TailLoop); @@ -37,7 +37,7 @@ impl DataflowOpTrait for TailLoop { impl TailLoop { /// Build the output TypeRow of the child graph of a TailLoop node. - pub(crate) fn body_output_row(&self) -> TypeRow { + pub(crate) fn body_output_row(&self) -> SimpleRow { let predicate = SimpleType::new_predicate([self.just_inputs.clone(), self.just_outputs.clone()]); let mut outputs = vec![predicate]; @@ -46,7 +46,7 @@ impl TailLoop { } /// Build the input TypeRow of the child graph of a TailLoop node. - pub(crate) fn body_input_row(&self) -> TypeRow { + pub(crate) fn body_input_row(&self) -> SimpleRow { predicate_first(&self.just_inputs, &self.rest) } } @@ -55,11 +55,11 @@ impl TailLoop { #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct Conditional { /// The possible rows of the predicate input - pub predicate_inputs: Vec>, + pub predicate_inputs: Vec, /// Remaining input types - pub other_inputs: TypeRow, + pub other_inputs: SimpleRow, /// Output types - pub outputs: TypeRow, + pub outputs: SimpleRow, } impl_op_name!(Conditional); @@ -82,7 +82,7 @@ impl DataflowOpTrait for Conditional { impl Conditional { /// Build the input TypeRow of the nth child graph of a Conditional node. - pub(crate) fn case_input_row(&self, case: usize) -> Option> { + pub(crate) fn case_input_row(&self, case: usize) -> Option { Some(predicate_first( self.predicate_inputs.get(case)?, &self.other_inputs, @@ -94,8 +94,8 @@ impl Conditional { #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] #[allow(missing_docs)] pub struct CFG { - pub inputs: TypeRow, - pub outputs: TypeRow, + pub inputs: SimpleRow, + pub outputs: SimpleRow, } impl_op_name!(CFG); @@ -119,13 +119,13 @@ impl DataflowOpTrait for CFG { pub enum BasicBlock { /// A CFG basic block node. The signature is that of the internal Dataflow graph. DFB { - inputs: TypeRow, - other_outputs: TypeRow, - predicate_variants: Vec>, + inputs: SimpleRow, + other_outputs: SimpleRow, + predicate_variants: Vec, }, /// The single exit node of the CFG, has no children, /// stores the types of the CFG node output. - Exit { cfg_outputs: TypeRow }, + Exit { cfg_outputs: SimpleRow }, } impl OpName for BasicBlock { @@ -169,7 +169,7 @@ impl OpTrait for BasicBlock { impl BasicBlock { /// The input signature of the contained dataflow graph. - pub fn dataflow_input(&self) -> &TypeRow { + pub fn dataflow_input(&self) -> &SimpleRow { match self { BasicBlock::DFB { inputs, .. } => inputs, BasicBlock::Exit { cfg_outputs } => cfg_outputs, @@ -178,7 +178,7 @@ impl BasicBlock { /// The correct inputs of any successors. Returns None if successor is not a /// valid index. - pub fn successor_input(&self, successor: usize) -> Option> { + pub fn successor_input(&self, successor: usize) -> Option { match self { BasicBlock::DFB { predicate_variants, @@ -215,18 +215,18 @@ impl OpTrait for Case { impl Case { /// The input signature of the contained dataflow graph. - pub fn dataflow_input(&self) -> &TypeRow { + pub fn dataflow_input(&self) -> &SimpleRow { &self.signature.input } /// The output signature of the contained dataflow graph. - pub fn dataflow_output(&self) -> &TypeRow { + pub fn dataflow_output(&self) -> &SimpleRow { &self.signature.output } } -fn predicate_first(pred: &TypeRow, rest: &TypeRow) -> TypeRow { - TypeRow::from( +fn predicate_first(pred: &ClassicRow, rest: &SimpleRow) -> SimpleRow { + SimpleRow::from( pred.iter() .cloned() .map(SimpleType::Classic) diff --git a/src/ops/dataflow.rs b/src/ops/dataflow.rs index 76018cae8..e56159bbb 100644 --- a/src/ops/dataflow.rs +++ b/src/ops/dataflow.rs @@ -4,7 +4,7 @@ use super::StaticTag; use super::{impl_op_name, OpTag, OpTrait}; use crate::resource::ResourceSet; -use crate::types::{ClassicType, EdgeKind, Signature, SimpleType, TypeRow}; +use crate::types::{ClassicType, EdgeKind, Signature, SimpleRow, SimpleType}; pub(super) trait DataflowOpTrait { const TAG: OpTag; @@ -31,7 +31,7 @@ pub(super) trait DataflowOpTrait { /// Helpers to construct input and output nodes pub trait IOTrait { /// Construct a new I/O node from a type row with no resource requirements - fn new(types: impl Into>) -> Self; + fn new(types: impl Into) -> Self; /// Helper method to add resource requirements to an I/O node fn with_resources(self, rs: ResourceSet) -> Self; } @@ -41,7 +41,7 @@ pub trait IOTrait { #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct Input { /// Input value types - pub types: TypeRow, + pub types: SimpleRow, /// Resources attached to output wires pub resources: ResourceSet, } @@ -49,7 +49,7 @@ pub struct Input { impl_op_name!(Input); impl IOTrait for Input { - fn new(types: impl Into>) -> Self { + fn new(types: impl Into) -> Self { Input { types: types.into(), resources: ResourceSet::new(), @@ -66,7 +66,7 @@ impl IOTrait for Input { #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct Output { /// Output value types - pub types: TypeRow, + pub types: SimpleRow, /// Resources expected from input wires pub resources: ResourceSet, } @@ -74,7 +74,7 @@ pub struct Output { impl_op_name!(Output); impl IOTrait for Output { - fn new(types: impl Into>) -> Self { + fn new(types: impl Into) -> Self { Output { types: types.into(), resources: ResourceSet::new(), @@ -99,7 +99,7 @@ impl DataflowOpTrait for Input { } fn signature(&self) -> Signature { - let mut sig = Signature::new_df(TypeRow::new(), self.types.clone()); + let mut sig = Signature::new_df(SimpleRow::new(), self.types.clone()); sig.output_resources = self.resources.clone(); sig } @@ -112,7 +112,7 @@ impl DataflowOpTrait for Output { } fn signature(&self) -> Signature { - let mut sig = Signature::new_df(self.types.clone(), TypeRow::new()); + let mut sig = Signature::new_df(self.types.clone(), SimpleRow::new()); sig.input_resources = self.resources.clone(); sig } @@ -212,7 +212,7 @@ impl DataflowOpTrait for LoadConstant { fn signature(&self) -> Signature { Signature::new( - TypeRow::new(), + SimpleRow::new(), vec![SimpleType::Classic(self.datatype.clone())], vec![self.datatype.clone()], ) diff --git a/src/ops/leaf.rs b/src/ops/leaf.rs index 4d4651219..99fc1dfc0 100644 --- a/src/ops/leaf.rs +++ b/src/ops/leaf.rs @@ -7,7 +7,7 @@ use super::{OpName, OpTag, OpTrait, StaticTag}; use crate::{ resource::{ResourceId, ResourceSet}, type_row, - types::{ClassicType, EdgeKind, Signature, SignatureDescription, SimpleType, TypeRow}, + types::{ClassicType, EdgeKind, Signature, SignatureDescription, SimpleRow, SimpleType}, }; /// Dataflow operations with no children. @@ -54,25 +54,25 @@ pub enum LeafOp { /// An operation that packs all its inputs into a tuple. MakeTuple { ///Tuple element types. - tys: TypeRow, + tys: SimpleRow, }, /// An operation that unpacks a tuple into its components. UnpackTuple { ///Tuple element types. - tys: TypeRow, + tys: SimpleRow, }, /// An operation that creates a tagged sum value from one of its variants. Tag { /// The variant to create. tag: usize, /// The variants of the sum type. - variants: TypeRow, + variants: SimpleRow, }, /// A node which adds a resource req to the types of the wires it is passed /// It has no effect on the values passed along the edge Lift { /// The types of the edges - type_row: TypeRow, + type_row: SimpleRow, /// The resources which are present in both the inputs and outputs input_resources: ResourceSet, /// The resources which we're adding to the inputs diff --git a/src/ops/validate.rs b/src/ops/validate.rs index 03d9b3465..4108a7326 100644 --- a/src/ops/validate.rs +++ b/src/ops/validate.rs @@ -10,7 +10,7 @@ use itertools::Itertools; use portgraph::{NodeIndex, PortOffset}; use thiserror::Error; -use crate::types::{ClassicType, SimpleType, TypeRow}; +use crate::types::{ClassicRow, SimpleRow, SimpleType}; use crate::Direction; use super::{impl_validate_op, BasicBlock, OpTag, OpTrait, OpType, ValidateOp}; @@ -242,8 +242,8 @@ pub enum ChildrenValidationError { #[error("The {node_desc} node of a {container_desc} has a signature of {actual:?}, which differs from the expected type row {expected:?}")] IOSignatureMismatch { child: NodeIndex, - actual: TypeRow, - expected: TypeRow, + actual: SimpleRow, + expected: SimpleRow, node_desc: &'static str, container_desc: &'static str, }, @@ -256,7 +256,7 @@ pub enum ChildrenValidationError { child: NodeIndex, expected_count: usize, actual_count: usize, - actual_predicate_rows: Vec>, + actual_predicate_rows: Vec, }, } @@ -343,8 +343,7 @@ impl ValidateOp for BasicBlock { other_outputs: outputs, } => { let predicate_type = SimpleType::new_predicate(predicate_variants.clone()); - let node_outputs: TypeRow = - [&[predicate_type], outputs.as_ref()].concat().into(); + let node_outputs: SimpleRow = [&[predicate_type], outputs.as_ref()].concat().into(); validate_io_nodes(inputs, &node_outputs, "basic block graph", children) } // Exit nodes do not have children @@ -384,8 +383,8 @@ impl ValidateOp for super::Case { /// nodes outside of the first and second elements respectively, and that those /// have the correct signature. fn validate_io_nodes<'a>( - expected_input: &TypeRow, - expected_output: &TypeRow, + expected_input: &SimpleRow, + expected_output: &SimpleRow, container_desc: &'static str, mut children: impl Iterator, ) -> Result<(), ChildrenValidationError> { diff --git a/src/resource.rs b/src/resource.rs index cdb52f125..87ec5ba07 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -14,9 +14,8 @@ use thiserror::Error; use crate::types::type_param::{check_type_arg, TypeArgError}; use crate::types::{ type_param::{TypeArg, TypeParam}, - Signature, SignatureDescription, + Signature, SignatureDescription, SimpleRow, }; -use crate::types::{SimpleType, TypeRow}; use crate::Hugr; /// Trait for resources to provide custom binary code for computing signature. @@ -29,7 +28,7 @@ pub trait CustomSignatureFunc: Send + Sync { name: &SmolStr, arg_values: &[TypeArg], misc: &HashMap, - ) -> Result<(TypeRow, TypeRow, ResourceSet), SignatureError>; + ) -> Result<(SimpleRow, SimpleRow, ResourceSet), SignatureError>; /// Describe the signature of a node, given the operation name, /// values for the type parameters, @@ -46,19 +45,14 @@ pub trait CustomSignatureFunc: Send + Sync { impl CustomSignatureFunc for F where - F: Fn( - &[TypeArg], - ) - -> Result<(TypeRow, TypeRow, ResourceSet), SignatureError> - + Send - + Sync, + F: Fn(&[TypeArg]) -> Result<(SimpleRow, SimpleRow, ResourceSet), SignatureError> + Send + Sync, { fn compute_signature( &self, _name: &SmolStr, arg_values: &[TypeArg], _misc: &HashMap, - ) -> Result<(TypeRow, TypeRow, ResourceSet), SignatureError> { + ) -> Result<(SimpleRow, SimpleRow, ResourceSet), SignatureError> { self(arg_values) } } diff --git a/src/types.rs b/src/types.rs index d1b78c39b..7a5f2fb10 100644 --- a/src/types.rs +++ b/src/types.rs @@ -11,7 +11,7 @@ use std::ops::Index; use pyo3::prelude::*; pub use custom::CustomType; -pub use simple::{ClassicType, Container, SimpleType, TypeRow}; +pub use simple::{ClassicRow, ClassicType, Container, SimpleRow, SimpleType}; use smol_str::SmolStr; @@ -19,7 +19,7 @@ use crate::hugr::{Direction, Port}; use crate::utils::display_list; use crate::{resource::ResourceSet, type_row}; -use self::simple::PrimType; +use self::simple::{PrimType, TypeRow}; /// The kinds of edges in a HUGR, excluding Hierarchy. //#[cfg_attr(feature = "pyo3", pyclass)] # TODO: Manually derive pyclass with non-unit variants @@ -52,11 +52,11 @@ impl EdgeKind { #[derive(Clone, Default, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct Signature { /// Value inputs of the function. - pub input: TypeRow, + pub input: SimpleRow, /// Value outputs of the function. - pub output: TypeRow, + pub output: SimpleRow, /// Possible static input (for call / load-constant). - pub static_input: TypeRow, + pub static_input: ClassicRow, /// The resource requirements of all the inputs pub input_resources: ResourceSet, /// The resource requirements of all the outputs @@ -211,9 +211,9 @@ impl Signature { impl Signature { /// Create a new signature. pub fn new( - input: impl Into>, - output: impl Into>, - static_input: impl Into>, + input: impl Into, + output: impl Into, + static_input: impl Into, ) -> Self { Self { input: input.into(), @@ -225,16 +225,13 @@ impl Signature { } /// Create a new signature with the same input and output types. - pub fn new_linear(linear: impl Into>) -> Self { + pub fn new_linear(linear: impl Into) -> Self { let linear = linear.into(); Signature::new_df(linear.clone(), linear) } /// Create a new signature with only dataflow inputs and outputs. - pub fn new_df( - input: impl Into>, - output: impl Into>, - ) -> Self { + pub fn new_df(input: impl Into, output: impl Into) -> Self { Signature::new(input, output, type_row![]) } } diff --git a/src/types/simple.rs b/src/types/simple.rs index be20bb85c..14721e5a2 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -154,12 +154,12 @@ impl ClassicType { /// New unit type, defined as an empty Tuple. pub fn new_unit() -> Self { - Self::Container(Container::Tuple(Box::new(TypeRow::new()))) + Self::Container(Container::Tuple(Box::new(classic_row![]))) } /// New Sum of Tuple types, used as predicates in branching. /// Tuple rows are defined in order by input rows. - pub fn new_predicate(variant_rows: impl IntoIterator>) -> Self { + pub fn new_predicate(variant_rows: impl IntoIterator) -> Self { Self::Container(Container::Sum(Box::new(TypeRow::predicate_variants_row( variant_rows, )))) @@ -234,7 +234,7 @@ impl SimpleType { /// New Sum of Tuple types, used as predicates in branching. /// Tuple rows are defined in order by input rows. - pub fn new_predicate(variant_rows: impl IntoIterator>) -> Self { + pub fn new_predicate(variant_rows: impl IntoIterator) -> Self { Self::Classic(ClassicType::new_predicate(variant_rows)) } @@ -282,6 +282,12 @@ pub struct TypeRow { types: Cow<'static, [T]>, } +/// A row of [SimpleType]s +pub type SimpleRow = TypeRow; + +/// A row of [ClassicType]s +pub type ClassicRow = TypeRow; + impl Display for TypeRow { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_char('[')?; @@ -317,9 +323,7 @@ impl TypeRow { #[inline] /// Return the type row of variants required to define a Sum of Tuples type /// given the rows of each tuple - pub fn predicate_variants_row( - variant_rows: impl IntoIterator>, - ) -> Self { + pub fn predicate_variants_row(variant_rows: impl IntoIterator) -> Self { variant_rows .into_iter() .map(|row| ClassicType::Container(Container::Tuple(Box::new(row)))) From 8696dad7d478dbbf50f7312d032fd36c786d686b Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 17 Jul 2023 17:38:14 +0100 Subject: [PATCH 39/47] fix doc links in macros.rs --- src/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index 690e73cc1..eb753ff94 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -37,8 +37,8 @@ pub(crate) use impl_box_clone; /// [`TypeRow::from`] instead. /// /// [`SimpleType`]: crate::types::SimpleType -/// [`TypeRow`]: crate::types::TypeRow -/// [`TypeRow::from`]: crate::types::TypeRow::from +/// [`TypeRow`]: crate::types::simple::TypeRow +/// [`TypeRow::from`]: crate::types::simple::TypeRow::from /// /// Example: /// ``` From e04294c6058229f4504af9f4a06b841fba03394c Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 17 Jul 2023 17:44:39 +0100 Subject: [PATCH 40/47] Properly doc classic_row! --- src/macros.rs | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index eb753ff94..bc1c3919a 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -28,25 +28,26 @@ macro_rules! impl_box_clone { } pub(crate) use impl_box_clone; -/// Creates a [`TypeRow`] backed by statically defined data, avoiding +/// Creates a [`SimpleRow`] backed by statically defined data, avoiding /// allocations. /// /// The parameters must be constants of type [`SimpleType`]. /// /// For type rows that cannot be statically defined, use a vector or slice with -/// [`TypeRow::from`] instead. +/// [`SimpleRow::from`] instead. /// /// [`SimpleType`]: crate::types::SimpleType -/// [`TypeRow`]: crate::types::simple::TypeRow -/// [`TypeRow::from`]: crate::types::simple::TypeRow::from +/// [`SimpleRow`]: crate::types::SimpleRow +/// [`SimpleRow::from`]: crate::types::SimpleRow::from /// /// Example: /// ``` /// # use hugr::macros::type_row; /// # use hugr::types::{ClassicType, SimpleType, Signature, SimpleRow}; /// const B: SimpleType = SimpleType::Classic(ClassicType::bit()); -/// let static_row: SimpleRow = type_row![B, B]; -/// let dynamic_row: SimpleRow = vec![B, B, B].into(); +/// const QB: SimpleType = SimpleType::Qubit; +/// let static_row: SimpleRow = type_row![B, QB]; +/// let dynamic_row: SimpleRow = vec![B, B, QB].into(); /// let sig: Signature = Signature::new_df(static_row.clone(), dynamic_row); /// /// let repeated_row: SimpleRow = type_row![B; 2]; @@ -78,9 +79,28 @@ macro_rules! type_row { }; } -/// Like [type_row!] but for rows of [ClassicType]s +/// Like [type_row!] but creates a [`ClassicRow`], from parameters +/// that must all be constants of type [`ClassicType`]. /// -/// [ClassicType]: crate::types::ClassicType +/// For type rows that cannot be statically defined, use a vector or slice with +/// [`ClassicRow::from`] instead. +/// +/// [`ClassicType`]: crate::types::ClassicType +/// [`ClassicRow`]: crate::types::ClassicRow +/// [`ClassicRow::from`]: crate::types::ClassicRow::from +/// +/// Example: +/// ``` +/// # use hugr::macros::type_row; +/// # use hugr::types::{ClassicType, SimpleType, Signature, SimpleRow}; +/// const B: ClassicType = ClassicType::bit(); +/// const I: ClassicType = ClassicType::int(64); +/// let static_row: ClassicRow = classic_row![B, QB]; +/// let dynamic_row: ClassicRow = vec![B, B, QB].into(); +/// +/// let repeated_row: SimpleRow = type_row![B; 2]; +/// assert_eq!(repeated_row, static_row); +/// ``` #[allow(unused_macros)] #[macro_export] macro_rules! classic_row { From d8023f9baa63379885fffb90abb6f5db80f904a0 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 17 Jul 2023 17:53:18 +0100 Subject: [PATCH 41/47] And more macro doc fixes --- src/macros.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index bc1c3919a..d74719d95 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -47,11 +47,11 @@ pub(crate) use impl_box_clone; /// const B: SimpleType = SimpleType::Classic(ClassicType::bit()); /// const QB: SimpleType = SimpleType::Qubit; /// let static_row: SimpleRow = type_row![B, QB]; -/// let dynamic_row: SimpleRow = vec![B, B, QB].into(); -/// let sig: Signature = Signature::new_df(static_row.clone(), dynamic_row); +/// let dynamic_row: SimpleRow = vec![B, B, B].into(); +/// let sig: Signature = Signature::new_df(static_row, dynamic_row); /// -/// let repeated_row: SimpleRow = type_row![B; 2]; -/// assert_eq!(repeated_row, static_row); +/// let repeated_row: SimpleRow = type_row![B; 3]; +/// assert_eq!(repeated_row, sig.output); /// ``` #[allow(unused_macros)] #[macro_export] @@ -91,14 +91,14 @@ macro_rules! type_row { /// /// Example: /// ``` -/// # use hugr::macros::type_row; -/// # use hugr::types::{ClassicType, SimpleType, Signature, SimpleRow}; +/// # use hugr::macros::classic_row; +/// # use hugr::types::{ClassicType, Signature, ClassicRow}; /// const B: ClassicType = ClassicType::bit(); -/// const I: ClassicType = ClassicType::int(64); -/// let static_row: ClassicRow = classic_row![B, QB]; -/// let dynamic_row: ClassicRow = vec![B, B, QB].into(); +/// const I: ClassicType = ClassicType::int::<2>(); +/// let static_row: ClassicRow = classic_row![B, B]; +/// let dynamic_row: ClassicRow = vec![B, B, I].into(); /// -/// let repeated_row: SimpleRow = type_row![B; 2]; +/// let repeated_row: ClassicRow = classic_row![B; 2]; /// assert_eq!(repeated_row, static_row); /// ``` #[allow(unused_macros)] @@ -121,7 +121,7 @@ macro_rules! classic_row { { use $crate::types; static ROW: &[types::ClassicType] = &[$t; $n]; - let row: types::TypeRow<_> = ROW.into(); + let row: types::ClassicRow = ROW.into(); row } }; From c71f6fe00b2a23af7d3746d4a67d1edcb814bff5 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Sun, 23 Jul 2023 09:30:48 +0100 Subject: [PATCH 42/47] fmt --- src/ops/constant.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ops/constant.rs b/src/ops/constant.rs index 738b45453..ff5ade486 100644 --- a/src/ops/constant.rs +++ b/src/ops/constant.rs @@ -5,7 +5,7 @@ use std::any::Any; use crate::{ classic_row, macros::impl_box_clone, - types::{ClassicRow, ClassicType, CustomType, Container, EdgeKind}, + types::{ClassicRow, ClassicType, Container, CustomType, EdgeKind}, }; use downcast_rs::{impl_downcast, Downcast}; From fecce95bd18ce2a9058ebbc116d5b90c8250a2d3 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Sun, 23 Jul 2023 09:35:39 +0100 Subject: [PATCH 43/47] fix doc --- src/ops/constant.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ops/constant.rs b/src/ops/constant.rs index ff5ade486..c5749dc3a 100644 --- a/src/ops/constant.rs +++ b/src/ops/constant.rs @@ -211,7 +211,7 @@ impl From for ConstValue { } } -/// Constant value for opaque [`SimpleType`]s. +/// Constant value for opaque [`CustomType`]s. /// /// When implementing this trait, include the `#[typetag::serde]` attribute to /// enable serialization. From c32bd452fcddbfc2c47110df02a4ce03575e3cea Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 24 Jul 2023 14:22:45 +0100 Subject: [PATCH 44/47] Test new_tuple and new_sum --- src/types/simple.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/types/simple.rs b/src/types/simple.rs index 14721e5a2..5318f632d 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -417,3 +417,42 @@ impl DerefMut for TypeRow { self.types.to_mut() } } + +#[cfg(test)] +mod test { + use super::*; + use cool_asserts::assert_matches; + + #[test] + fn new_tuple() { + let simp = vec![SimpleType::Qubit, SimpleType::Classic(ClassicType::Int(4))]; + let ty = SimpleType::new_tuple(simp); + assert_matches!(ty, SimpleType::Qontainer(Container::Tuple(_))); + + let clas: ClassicRow = vec![ + ClassicType::F64, + ClassicType::Container(Container::List(Box::new(ClassicType::F64))), + ] + .into(); + let ty = SimpleType::new_tuple(clas.map_into()); + assert_matches!( + ty, + SimpleType::Classic(ClassicType::Container(Container::Tuple(_))) + ); + } + + #[test] + fn new_sum() { + let clas = vec![ + SimpleType::Classic(ClassicType::F64), + SimpleType::Classic(ClassicType::Container(Container::List(Box::new( + ClassicType::F64, + )))), + ]; + let ty = SimpleType::new_sum(clas); + assert_matches!( + ty, + SimpleType::Classic(ClassicType::Container(Container::Sum(_))) + ); + } +} From b6f023c8efe0f4345255371259202ad090600c77 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 24 Jul 2023 21:00:48 +0100 Subject: [PATCH 45/47] Combine impl blocks --- src/types/simple.rs | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/types/simple.rs b/src/types/simple.rs index 5318f632d..e2305785f 100644 --- a/src/types/simple.rs +++ b/src/types/simple.rs @@ -296,21 +296,6 @@ impl Display for TypeRow { } } -//#[cfg_attr(feature = "pyo3", pymethods)] // TODO: expose unparameterized versions -impl TypeRow { - /// Returns the number of types in the row. - #[inline(always)] - pub fn len(&self) -> usize { - self.types.len() - } - - /// Returns `true` if the row contains no types. - #[inline(always)] - pub fn is_empty(&self) -> bool { - self.types.len() == 0 - } -} - impl TypeRow { /// Returns whether the row contains only classic data. #[inline(always)] @@ -332,6 +317,8 @@ impl TypeRow { } } +// TODO some of these, but not all, will probably want exposing via +// pyo3 wrappers eventually. impl TypeRow { /// Create a new empty row. pub const fn new() -> Self { @@ -345,6 +332,18 @@ impl TypeRow { self.types.iter() } + /// Returns the number of types in the row. + #[inline(always)] + pub fn len(&self) -> usize { + self.types.len() + } + + /// Returns `true` if the row contains no types. + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.types.len() == 0 + } + /// Mutable iterator over the types in the row. pub fn to_mut(&mut self) -> &mut Vec { self.types.to_mut() From ea976ba602469aca7061621f07d8bb70939b3d45 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 24 Jul 2023 21:14:19 +0100 Subject: [PATCH 46/47] types: export PrimType, TypeRow --- src/types.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/types.rs b/src/types.rs index 7a5f2fb10..ec65b3052 100644 --- a/src/types.rs +++ b/src/types.rs @@ -11,7 +11,7 @@ use std::ops::Index; use pyo3::prelude::*; pub use custom::CustomType; -pub use simple::{ClassicRow, ClassicType, Container, SimpleRow, SimpleType}; +pub use simple::{ClassicRow, ClassicType, Container, PrimType, SimpleRow, SimpleType, TypeRow}; use smol_str::SmolStr; @@ -19,8 +19,6 @@ use crate::hugr::{Direction, Port}; use crate::utils::display_list; use crate::{resource::ResourceSet, type_row}; -use self::simple::{PrimType, TypeRow}; - /// The kinds of edges in a HUGR, excluding Hierarchy. //#[cfg_attr(feature = "pyo3", pyclass)] # TODO: Manually derive pyclass with non-unit variants #[derive(Clone, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)] From f4dcd896ea894c4b3ee2e2ff8504f9a2743f85be Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Mon, 24 Jul 2023 21:14:33 +0100 Subject: [PATCH 47/47] tidy some imports --- src/builder/cfg.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/builder/cfg.rs b/src/builder/cfg.rs index 425460d57..85df2a4f6 100644 --- a/src/builder/cfg.rs +++ b/src/builder/cfg.rs @@ -7,18 +7,12 @@ use super::{ BasicBlockID, BuildError, CfgID, Container, Dataflow, HugrBuilder, Wire, }; -use crate::{ - hugr::view::HugrView, - type_row, - types::{ClassicRow, SimpleRow, SimpleType}, -}; - +use crate::hugr::view::HugrView; +use crate::hugr::HugrMut; use crate::ops::handle::NodeHandle; use crate::ops::{self, BasicBlock, OpType}; -use crate::types::Signature; - -use crate::Node; -use crate::{hugr::HugrMut, Hugr}; +use crate::types::{ClassicRow, Signature, SimpleRow, SimpleType}; +use crate::{type_row, Hugr, Node}; /// Builder for a [`crate::ops::CFG`] child control /// flow graph