Skip to content

Commit

Permalink
Move Type, TypeBound, PrimType to better locations (#403)
Browse files Browse the repository at this point in the history
namely Type, TypeBound -> types.rs
PrimType -> primitive.rs

also add docstrings
  • Loading branch information
ss2165 authored Aug 11, 2023
1 parent 3c2acec commit 7366c2f
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 204 deletions.
188 changes: 185 additions & 3 deletions src/types.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
//! General wire types used in the compiler

pub mod custom;
pub mod leaf;
mod primitive;
mod serialize;
mod signature;
pub mod simple;
pub mod type_enum;
pub mod type_param;
pub mod type_row;

Expand Down Expand Up @@ -90,9 +90,191 @@ impl TypeTag {
}
}

use itertools::FoldWhile::{Continue, Done};
use itertools::Itertools;
use serde::{Deserialize, Serialize};

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, derive_more::Display, Serialize, Deserialize)]
/// Bounds on capabilities of a type.
pub enum TypeBound {
/// The equality operation is valid on this type.
#[serde(rename = "E")]
Eq,
/// The type can be copied in the program.
#[serde(rename = "C")]
Copyable,
}

impl TypeBound {
/// Returns the smallest TypeTag containing both the receiver and argument.
/// (This will be one of the receiver or the argument.)
pub fn union(self, other: Self) -> Self {
if self.contains(other) {
self
} else {
debug_assert!(other.contains(self));
other
}
}

/// Report if this bound contains another.
pub fn contains(&self, other: TypeBound) -> bool {
use TypeBound::*;
match (self, other) {
(Copyable, Eq) => true,
(Eq, Copyable) => false,
_ => true,
}
}
}

/// Calculate the least upper bound for an iterator of bounds
fn least_upper_bound(mut tags: impl Iterator<Item = Option<TypeBound>>) -> Option<TypeBound> {
tags.fold_while(Some(TypeBound::Eq), |acc, new| {
if let (Some(acc), Some(new)) = (acc, new) {
Continue(Some(acc.union(new)))
} else {
// if any type is unbounded, short-circuit
Done(None)
}
})
.into_inner()
}

use std::fmt::Write;

use crate::{ops::AliasDecl, resource::PRELUDE, utils::display_list};
use std::fmt::{self, Debug, Display};

use self::type_param::TypeArg;

//TODO remove
type NewPrimType = primitive::PrimType;

#[derive(Clone, PartialEq, Debug, Eq, derive_more::Display)]
enum TypeEnum {
Prim(NewPrimType),
#[display(fmt = "Tuple({})", "DisplayRow(_0)")]
Tuple(Vec<Type>),
#[display(fmt = "Sum({})", "DisplayRow(_0)")]
Sum(Vec<Type>),
}
impl TypeEnum {
fn least_upper_bound(&self) -> Option<TypeBound> {
match self {
TypeEnum::Prim(p) => p.bound(),
TypeEnum::Tuple(ts) => least_upper_bound(ts.iter().map(Type::least_upper_bound)),
TypeEnum::Sum(ts) => least_upper_bound(ts.iter().map(Type::least_upper_bound)),
}
}
}

#[derive(
Clone, PartialEq, Debug, Eq, derive_more::Display, serde::Serialize, serde::Deserialize,
)]
#[display(fmt = "{}", "_0")]
#[serde(into = "serialize::SerSimpleType", from = "serialize::SerSimpleType")]
/// A HUGR type.
pub struct Type(TypeEnum, Option<TypeBound>);

struct DisplayRow<'a>(&'a Vec<Type>);
impl<'a> Display for DisplayRow<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_char('[')?;
display_list(self.0, f)?;
f.write_char(']')
}
}

impl Type {
/// Initialize a new graph type with a signature.
pub fn graph(signature: AbstractSignature) -> Self {
Self::new(TypeEnum::Prim(NewPrimType::Graph(Box::new(signature))))
}

/// Initialize a new usize type.
pub fn usize() -> Self {
Self::new_extension(
PRELUDE
.get_type("usize")
.unwrap()
.instantiate_concrete(vec![])
.unwrap(),
)
}

/// Initialize a new tuple type by providing the elements..
pub fn new_tuple(types: impl IntoIterator<Item = Type>) -> Self {
Self::new(TypeEnum::Tuple(types.into_iter().collect()))
}

/// New unit type, defined as an empty Tuple.
pub fn new_unit() -> Self {
Self::new_tuple(vec![])
}

/// Initialize a new sum type by providing the possible variant types.
pub fn new_sum(types: impl IntoIterator<Item = Type>) -> Self {
Self::new(TypeEnum::Sum(types.into_iter().collect()))
}

/// Initialize a new custom type.
// TODO remove? Resources/TypeDefs should just provide `Type` directly
pub fn new_extension(opaque: CustomType) -> Self {
Self::new(TypeEnum::Prim(NewPrimType::E(Box::new(opaque))))
}

/// Initialize a new alias.
pub fn new_alias(alias: AliasDecl) -> Self {
Self::new(TypeEnum::Prim(NewPrimType::A(alias)))
}

fn new(type_e: TypeEnum) -> Self {
let bound = type_e.least_upper_bound();
Self(type_e, bound)
}

/// Initialize a new array of type `typ` of length `size`
pub fn new_array(typ: Type, size: u64) -> Self {
let array_def = PRELUDE.get_type("array").unwrap();
// TODO replace with new Type
let custom_t = array_def
.instantiate_concrete(vec![TypeArg::Type(todo!()), TypeArg::USize(size)])
.unwrap();
Self::new_extension(custom_t)
}
/// New Sum of Tuple types, used as predicates in branching.
/// Tuple rows are defined in order by input rows.
pub fn new_predicate<V>(variant_rows: impl IntoIterator<Item = V>) -> Self
where
V: IntoIterator<Item = Type>,
{
Self::new_sum(predicate_variants_row(variant_rows))
}

/// New simple predicate with empty Tuple variants
pub fn new_simple_predicate(size: usize) -> Self {
Self::new_predicate(std::iter::repeat(vec![]).take(size))
}

/// Report the least upper TypeBound, if there is one.
pub fn least_upper_bound(&self) -> Option<TypeBound> {
self.1
}
}

/// Return the type row of variants required to define a Sum of Tuples type
/// given the rows of each tuple
pub(crate) fn predicate_variants_row<V>(variant_rows: impl IntoIterator<Item = V>) -> Vec<Type>
where
V: IntoIterator<Item = Type>,
{
variant_rows.into_iter().map(Type::new_tuple).collect()
}

#[cfg(test)]
mod test {
use crate::{ops::AliasDecl, types::type_enum::Type};
use crate::ops::AliasDecl;

use super::*;
#[test]
Expand Down
74 changes: 0 additions & 74 deletions src/types/leaf.rs

This file was deleted.

28 changes: 28 additions & 0 deletions src/types/primitive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//! Primitive types which are leaves of the type tree

use crate::ops::AliasDecl;

use super::{AbstractSignature, CustomType, TypeBound};

#[derive(
Clone, PartialEq, Debug, Eq, derive_more::Display, serde::Serialize, serde::Deserialize,
)]
pub(super) enum PrimType {
E(Box<CustomType>),
#[display(fmt = "Alias({})", "_0.name()")]
A(AliasDecl),
#[display(fmt = "Graph({})", "_0")]
Graph(Box<AbstractSignature>),
}

impl PrimType {
pub(super) fn bound(&self) -> Option<TypeBound> {
// TODO update once inner types are updated to new TypeBound
return None;
match self {
PrimType::E(_c) => todo!(),
PrimType::A(_) => todo!(),
PrimType::Graph(_) => Some(TypeBound::Copyable),
}
}
}
8 changes: 4 additions & 4 deletions src/types/type_enum/serialize.rs → src/types/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ use super::{Type, TypeEnum};

use itertools::Itertools;

use super::super::custom::CustomType;
use super::custom::CustomType;

use super::super::AbstractSignature;
use super::AbstractSignature;

use crate::ops::AliasDecl;
use crate::types::leaf::PrimType;
use crate::types::primitive::PrimType;

#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
#[serde(tag = "t")]
Expand Down Expand Up @@ -58,8 +58,8 @@ impl From<SerSimpleType> for Type {
mod test {
use crate::hugr::serialize::test::ser_roundtrip;
use crate::types::custom::test::CLASSIC_CUST;
use crate::types::type_enum::Type;
use crate::types::AbstractSignature;
use crate::types::Type;

#[test]
fn serialize_types_roundtrip() {
Expand Down
Loading

0 comments on commit 7366c2f

Please sign in to comment.