Skip to content

Commit

Permalink
feat!: opaque type arguments are untyped bytes.
Browse files Browse the repository at this point in the history
Closes #1308

- Previously held a yaml value, this doesn't really make much sense
- If it is an opaque blob, no reason it needs a HUGR custom type attached to it?
- Now truly opaque, it is up to extension-aware tooling to use the bytes data as they see fit
- Serialised as base64 encoded string
- Utilities for common case, strings
- Conducive with adding typed "operation intrinsics/properties" as a follow-up. This would be hugr-typed values that can be attached to operations (in a semantically significant manner, unlike metadata) but perhaps are not allowed to affect the signature.
- should there be a cap on size of byte array? If so should we use `[u8; N]` over `Vec<u8>`?
- Serialisation break to be handled TODO

BREAKING_CHANGE: opaque type arguments are now untyped and hold bytes rather than a yaml value. Serialised form is base64 string.
  • Loading branch information
ss2165 committed Jul 19, 2024
1 parent 01da7ba commit c3e1b23
Show file tree
Hide file tree
Showing 16 changed files with 313 additions and 353 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ rstest = "0.21.0"
serde = "1.0"
serde_json = "1.0.97"
serde_yaml = "0.9.19"
serde_with = { version = "3.9.0", features = ["base64"] }
smol_str = "0.2.0"
strum = "0.26.1"
strum_macros = "0.26.1"
Expand Down
1 change: 1 addition & 0 deletions hugr-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ delegate = { workspace = true }
paste = { workspace = true }
strum = { workspace = true }
strum_macros = { workspace = true }
serde_with = { workspace = true }

[dev-dependencies]
rstest = { workspace = true }
Expand Down
6 changes: 3 additions & 3 deletions hugr-core/src/extension/declarative.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,13 +313,13 @@ extensions:
- name: MyType
description: A simple type with no parameters
# Parametric types are not currently supported.
params: [Any, ["An unbounded natural number", USize]]
# params: [Any]
operations:
- name: UnsupportedOperation
description: An operation from 3 qubits to 3 qubits
params:
# params:
# Parametric operations are not currently supported.
param1: USize
# param1: USize
signature:
# Type declarations will have their own syntax.
inputs: []
Expand Down
58 changes: 6 additions & 52 deletions hugr-core/src/extension/declarative/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

use crate::extension::{TypeDef, TypeDefBound};
use crate::types::type_param::TypeParam;
use crate::types::{CustomType, TypeBound, TypeName};
use crate::types::{TypeBound, TypeName};
use crate::Extension;

use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -100,14 +100,11 @@ impl From<TypeDefBoundDeclaration> for TypeDefBound {

/// A declarative type parameter definition.
///
/// Either a type, or a 2-element list containing a human-readable name and a type id.
/// Only supports opaque parameters for now.
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
enum TypeParamDeclaration {
/// Just the type id.
Type(TypeName),
/// A 2-tuple containing a human-readable name and a type id.
WithDescription(String, TypeName),
Opaque,
}

impl TypeParamDeclaration {
Expand All @@ -119,52 +116,9 @@ impl TypeParamDeclaration {
/// TODO: The parameter description is currently ignored.
pub fn make_type_param(
&self,
extension: &Extension,
ctx: DeclarationContext<'_>,
_extension: &Extension,
_ctx: DeclarationContext<'_>,
) -> Result<TypeParam, ExtensionDeclarationError> {
let instantiate_type = |ty: &TypeDef| -> Result<CustomType, ExtensionDeclarationError> {
match ty.params() {
[] => Ok(ty.instantiate([]).unwrap()),
_ => Err(ExtensionDeclarationError::ParametricTypeParameter {
ext: extension.name().clone(),
ty: self.type_name().clone(),
}),
}
};

// First try the previously defined types in the current extension.
if let Some(ty) = extension.get_type(self.type_name()) {
return Ok(TypeParam::Opaque {
ty: instantiate_type(ty)?,
});
}

// Try every extension in scope.
//
// TODO: Can we resolve the extension id from the type name instead?
for ext in ctx.scope.iter() {
if let Some(ty) = ctx
.registry
.get(ext)
.and_then(|ext| ext.get_type(self.type_name()))
{
return Ok(TypeParam::Opaque {
ty: instantiate_type(ty)?,
});
}
}

Err(ExtensionDeclarationError::MissingType {
ext: extension.name().clone(),
ty: self.type_name().clone(),
})
}

/// Returns the type name of this type parameter.
fn type_name(&self) -> &TypeName {
match self {
Self::Type(ty) => ty,
Self::WithDescription(_, ty) => ty,
}
Ok(TypeParam::Opaque)
}
}
6 changes: 3 additions & 3 deletions hugr-core/src/hugr/serialize/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::ops::custom::{ExtensionOp, OpaqueOp};
use crate::ops::{self, dataflow::IOTrait, Input, Module, Noop, Output, Value, DFG};
use crate::std_extensions::arithmetic::float_types::FLOAT64_TYPE;
use crate::std_extensions::arithmetic::int_ops::INT_OPS_REGISTRY;
use crate::std_extensions::arithmetic::int_types::{int_custom_type, ConstInt, INT_TYPES};
use crate::std_extensions::arithmetic::int_types::{ConstInt, INT_TYPES};
use crate::std_extensions::logic::NotOp;
use crate::types::type_param::TypeParam;
use crate::types::{
Expand Down Expand Up @@ -453,7 +453,7 @@ fn polyfunctype2() -> PolyFuncTypeRV {
#[rstest]
#[case(Signature::new_endo(type_row![]).into())]
#[case(polyfunctype1())]
#[case(PolyFuncType::new([TypeParam::Opaque { ty: int_custom_type(TypeArg::BoundedNat { n: 1 }) }], Signature::new_endo(type_row![Type::new_var_use(0, TypeBound::Copyable)])))]
#[case(PolyFuncType::new([TypeParam::Opaque], Signature::new_endo(type_row![Type::new_var_use(0, TypeBound::Copyable)])))]
#[case(PolyFuncType::new([TypeBound::Eq.into()], Signature::new_endo(type_row![Type::new_var_use(0, TypeBound::Eq)])))]
#[case(PolyFuncType::new([TypeParam::new_list(TypeBound::Any)], Signature::new_endo(type_row![])))]
#[case(PolyFuncType::new([TypeParam::Tuple { params: [TypeBound::Any.into(), TypeParam::bounded_nat(2.try_into().unwrap())].into() }], Signature::new_endo(type_row![])))]
Expand All @@ -466,7 +466,7 @@ fn roundtrip_polyfunctype_fixedlen(#[case] poly_func_type: PolyFuncType) {

#[rstest]
#[case(FuncValueType::new_endo(type_row![]).into())]
#[case(PolyFuncTypeRV::new([TypeParam::Opaque { ty: int_custom_type(TypeArg::BoundedNat { n: 1 }) }], FuncValueType::new_endo(type_row![Type::new_var_use(0, TypeBound::Copyable)])))]
#[case(PolyFuncTypeRV::new([TypeParam::Opaque], FuncValueType::new_endo(type_row![Type::new_var_use(0, TypeBound::Copyable)])))]
#[case(PolyFuncTypeRV::new([TypeBound::Eq.into()], FuncValueType::new_endo(type_row![Type::new_var_use(0, TypeBound::Eq)])))]
#[case(PolyFuncTypeRV::new([TypeParam::new_list(TypeBound::Any)], FuncValueType::new_endo(type_row![])))]
#[case(PolyFuncTypeRV::new([TypeParam::Tuple { params: [TypeBound::Any.into(), TypeParam::bounded_nat(2.try_into().unwrap())].into() }], FuncValueType::new_endo(type_row![])))]
Expand Down
4 changes: 2 additions & 2 deletions hugr-core/src/types/poly_func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ pub(crate) mod test {
use cool_asserts::assert_matches;
use lazy_static::lazy_static;

use crate::extension::prelude::{BOOL_T, PRELUDE_ID, USIZE_CUSTOM_T, USIZE_T};
use crate::extension::prelude::{BOOL_T, PRELUDE_ID, USIZE_T};
use crate::extension::{
ExtensionId, ExtensionRegistry, SignatureError, TypeDefBound, EMPTY_REG, PRELUDE,
PRELUDE_REGISTRY,
Expand Down Expand Up @@ -277,7 +277,7 @@ pub(crate) mod test {
TypeParam::List {
param: Box::new(TypeParam::max_nat()),
},
TypeParam::Opaque { ty: USIZE_CUSTOM_T },
TypeParam::Opaque,
TypeParam::Tuple {
params: vec![TypeBound::Any.into(), TypeParam::max_nat()],
},
Expand Down
Loading

0 comments on commit c3e1b23

Please sign in to comment.