Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move Type, TypeBound, PrimType to better locations #403

Merged
merged 4 commits into from
Aug 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a key thing in the public API, so it will need a more extensive explanation in the future.

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