diff --git a/specification/hugr.md b/specification/hugr.md index 351841181..7740f6477 100644 --- a/specification/hugr.md +++ b/specification/hugr.md @@ -127,9 +127,10 @@ 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) or a `LinearType` (data which cannot be copied, -including quantum data). A `Static` edge can only carry a `ClassicType`. For +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. As well as the type, dataflow edges are also parametrized by a @@ -144,7 +145,7 @@ As well as the type, dataflow edges are also parametrized by a [Non-local Edges](#non-local-edges) ``` -SimpleType ::= ClassicType | LinearType +SimpleType ⊃ ClassicType -- In the absence of unicode: "SimpleType is a superset of ClassicType" EdgeKind ::= Hierarchy | Value(Locality, SimpleType) | Static(Local | Ext, ClassicType) | Order | ControlFlow @@ -163,7 +164,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). @@ -990,12 +991,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) @@ -1009,9 +1009,10 @@ ClassicType ::= int | Graph[R](#, #) | Opaque(Name, #) | Container(ClassicType) -LinearType ::= Qubit +SimpleType ::= Qubit | QPaque(Name, #) - | Container(LinearType) + | Container(SimpleType) -- Sometimes called 'Qontainer' + | ClassicType ``` SimpleTypes are the types of *values* which can be sent down wires, @@ -1034,8 +1035,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. Note: any array can be turned into an equivalent tuple, but arrays also support dynamically-indexed `get`. (TODO: Indexed by u64, with panic if @@ -1055,18 +1056,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). +must have exactly one edge leaving them unless they are `ClassicType`, where +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. 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. +# 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 @@ -1096,20 +1098,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 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 12e42ee19..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,11 +646,9 @@ 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 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. - if let SimpleType::Linear(lty) = typ { - return Err(BuildError::NoCopyLinear(lty)); - } + return Err(BuildError::NoCopyLinear(typ)); } } diff --git a/src/builder/dataflow.rs b/src/builder/dataflow.rs index 2af825edf..690932c2b 100644 --- a/src/builder/dataflow.rs +++ b/src/builder/dataflow.rs @@ -197,6 +197,7 @@ mod test { use crate::ops::handle::NodeHandle; use crate::ops::OpTag; use crate::ops::OpTrait; + use crate::types::SimpleType; use crate::{ builder::{ test::{n_identity, BIT, NAT, QB}, @@ -205,7 +206,7 @@ mod test { ops::LeafOp, resource::ResourceSet, type_row, - types::{LinearType, Signature}, + types::Signature, Wire, }; @@ -306,7 +307,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/builder/module_builder.rs b/src/builder/module_builder.rs index fbfb7a30e..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_linear(); + 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/hugr/region.rs b/src/hugr/region.rs index a00c0ca3a..3c8471e1a 100644 --- a/src/hugr/region.rs +++ b/src/hugr/region.rs @@ -415,13 +415,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 8a544d774..b181173be 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::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 a26c4e9fa..c33e9a25f 100644 --- a/src/hugr/validate.rs +++ b/src/hugr/validate.rs @@ -742,13 +742,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/handle.rs b/src/ops/handle.rs index 4cb358aa8..7337ef79b 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; @@ -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/leaf.rs b/src/ops/leaf.rs index 98f935c48..0861a7bdf 100644 --- a/src/ops/leaf.rs +++ b/src/ops/leaf.rs @@ -7,9 +7,7 @@ use super::{OpName, OpTag, OpTrait, StaticTag}; 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, } } } @@ -157,7 +155,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); @@ -219,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/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); diff --git a/src/types.rs b/src/types.rs index d755b1f8b..32086db8e 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; @@ -35,10 +35,10 @@ 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_linear(), + EdgeKind::Value(t) => !t.is_classical(), _ => false, } } @@ -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 { @@ -82,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() { diff --git a/src/types/simple.rs b/src/types/simple.rs index f06738060..0f1161932 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,10 +24,14 @@ 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), + /// 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,19 +40,21 @@ 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), } } } -/// 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 - 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. @@ -91,10 +97,10 @@ impl From> for SimpleType { } } -impl From> for SimpleType { +impl From> for SimpleType { #[inline] - fn from(value: Container) -> Self { - Self::Linear(LinearType::Container(value)) + fn from(value: Container) -> Self { + Self::Qontainer(value) } } @@ -191,44 +197,14 @@ impl Display for ClassicType { } impl PrimType for ClassicType { - const LINEAR: bool = false; + const CLASSIC: bool = true; } -/// A type that represents concrete linear data. -/// -// 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 LinearType { - const LINEAR: bool = true; +impl PrimType for SimpleType { + const CLASSIC: bool = false; } impl SimpleType { - /// Returns whether the type contains only linear data. - pub fn is_linear(&self) -> bool { - matches!(self, Self::Linear(_)) - } - /// Returns whether the type contains only classic data. pub fn is_classical(&self) -> bool { matches!(self, Self::Classic(_)) @@ -240,7 +216,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 +226,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() } } @@ -266,51 +242,33 @@ impl SimpleType { } } -impl Default for SimpleType { - fn default() -> Self { - Self::Linear(Default::default()) +impl From for SimpleType { + fn from(typ: ClassicType) -> Self { + SimpleType::Classic(typ) } } -/// 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 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 -); -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)] @@ -344,12 +302,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 { @@ -364,17 +316,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() @@ -420,7 +361,9 @@ where T: Into>, { fn from(types: T) -> Self { - Self::from(types.into()) + Self { + types: types.into(), + } } } diff --git a/src/types/simple/serialize.rs b/src/types/simple/serialize.rs index 394687491..2e3659020 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; @@ -71,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 }, } } } @@ -116,24 +118,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 +150,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(), @@ -167,7 +161,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 +169,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,15 +192,15 @@ 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 { custom: c, l: true } => SimpleType::Qpaque(c), SerSimpleType::Opaque { custom: c, l: false,