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

feat!: remove the Eq type bound. #1364

Merged
merged 11 commits into from
Jul 26, 2024
2 changes: 1 addition & 1 deletion hugr-core/examples/extension/declarative.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ extensions:
# Parameters are not currently supported.
name: CopyableType
description: A simple type with no parameters
# Types may have a "Eq", "Copyable", or "Any" bound.
# Types may have a "Copyable", or "Any" bound.
# This field is optional and defaults to "Any".
bound: Copyable
operations:
Expand Down
3 changes: 0 additions & 3 deletions hugr-core/src/extension/declarative/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,6 @@ impl TypeDeclaration {
Debug, Copy, Clone, Serialize, Deserialize, Hash, PartialEq, Eq, Default, derive_more::Display,
)]
enum TypeDefBoundDeclaration {
/// The equality operation is valid on this type.
Eq,
/// The type can be copied in the program.
Copyable,
/// No bound on the type.
Expand All @@ -91,7 +89,6 @@ enum TypeDefBoundDeclaration {
impl From<TypeDefBoundDeclaration> for TypeDefBound {
fn from(bound: TypeDefBoundDeclaration) -> Self {
match bound {
TypeDefBoundDeclaration::Eq => Self::Explicit(TypeBound::Eq),
TypeDefBoundDeclaration::Copyable => Self::Explicit(TypeBound::Copyable),
TypeDefBoundDeclaration::Any => Self::Explicit(TypeBound::Any),
}
Expand Down
12 changes: 6 additions & 6 deletions hugr-core/src/extension/op_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ pub(super) mod test {
assert_eq!(def.validate_args(&args, &PRELUDE_REGISTRY, &[]), Ok(()));

// Second arg may be a variable (substitutable)
let tyvar = Type::new_var_use(0, TypeBound::Eq);
let tyvar = Type::new_var_use(0, TypeBound::Copyable);
let tyvars: Vec<Type> = vec![tyvar.clone(); 3];
let args = [TypeArg::BoundedNat { n: 3 }, tyvar.clone().into()];
assert_eq!(
Expand All @@ -684,15 +684,15 @@ pub(super) mod test {
.with_extension_delta(EXT_ID)
)
);
def.validate_args(&args, &PRELUDE_REGISTRY, &[TypeBound::Eq.into()])
def.validate_args(&args, &PRELUDE_REGISTRY, &[TypeBound::Copyable.into()])
.unwrap();

// quick sanity check that we are validating the args - note changed bound:
assert_eq!(
def.validate_args(&args, &PRELUDE_REGISTRY, &[TypeBound::Any.into()]),
Err(SignatureError::TypeVarDoesNotMatchDeclaration {
actual: TypeBound::Any.into(),
cached: TypeBound::Eq.into()
cached: TypeBound::Copyable.into()
})
);

Expand Down Expand Up @@ -729,16 +729,16 @@ pub(super) mod test {
Signature::new_endo(vec![Type::new_var_use(0, TypeBound::Any)]),
),
)?;
let tv = Type::new_var_use(1, TypeBound::Eq);
let tv = Type::new_var_use(1, TypeBound::Copyable);
let args = [TypeArg::Type { ty: tv.clone() }];
let decls = [TypeParam::Extensions, TypeBound::Eq.into()];
let decls = [TypeParam::Extensions, TypeBound::Copyable.into()];
def.validate_args(&args, &EMPTY_REG, &decls).unwrap();
assert_eq!(
def.compute_signature(&args, &EMPTY_REG),
Ok(Signature::new_endo(tv).with_extension_delta(EXT_ID))
);
// But not with an external row variable
let arg: TypeArg = TypeRV::new_row_var_use(0, TypeBound::Eq).into();
let arg: TypeArg = TypeRV::new_row_var_use(0, TypeBound::Copyable).into();
assert_eq!(
def.compute_signature(&[arg.clone()], &EMPTY_REG),
Err(SignatureError::TypeArgMismatch(
Expand Down
17 changes: 10 additions & 7 deletions hugr-core/src/extension/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,14 @@ lazy_static! {
TypeName::new_inline("usize"),
vec![],
"usize".into(),
TypeDefBound::Explicit(crate::types::TypeBound::Eq),
TypeDefBound::Explicit(crate::types::TypeBound::Copyable),
)
.unwrap();
prelude.add_type(
STRING_TYPE_NAME,
vec![],
"string".into(),
TypeDefBound::Explicit(crate::types::TypeBound::Eq),
TypeDefBound::Explicit(crate::types::TypeBound::Copyable),
)
.unwrap();
prelude.add_op(
Expand Down Expand Up @@ -137,7 +137,7 @@ lazy_static! {
ERROR_TYPE_NAME,
vec![],
"Simple opaque error type.".into(),
TypeDefBound::Explicit(TypeBound::Eq),
TypeDefBound::Explicit(TypeBound::Copyable),
)
.unwrap();
prelude
Expand All @@ -158,8 +158,11 @@ lazy_static! {

}

pub(crate) const USIZE_CUSTOM_T: CustomType =
CustomType::new_simple(TypeName::new_inline("usize"), PRELUDE_ID, TypeBound::Eq);
pub(crate) const USIZE_CUSTOM_T: CustomType = CustomType::new_simple(
TypeName::new_inline("usize"),
PRELUDE_ID,
TypeBound::Copyable,
);

pub(crate) const QB_CUSTOM_T: CustomType =
CustomType::new_simple(TypeName::new_inline("qubit"), PRELUDE_ID, TypeBound::Any);
Expand Down Expand Up @@ -214,7 +217,7 @@ pub const STRING_TYPE_NAME: TypeName = TypeName::new_inline("string");

/// Custom type for strings.
pub const STRING_CUSTOM_TYPE: CustomType =
CustomType::new_simple(STRING_TYPE_NAME, PRELUDE_ID, TypeBound::Eq);
CustomType::new_simple(STRING_TYPE_NAME, PRELUDE_ID, TypeBound::Copyable);

/// String type.
pub const STRING_TYPE: Type = Type::new_extension(STRING_CUSTOM_TYPE);
Expand Down Expand Up @@ -259,7 +262,7 @@ pub const PRINT_OP_ID: OpName = OpName::new_inline("print");

/// The custom type for Errors.
pub const ERROR_CUSTOM_TYPE: CustomType =
CustomType::new_simple(ERROR_TYPE_NAME, PRELUDE_ID, TypeBound::Eq);
CustomType::new_simple(ERROR_TYPE_NAME, PRELUDE_ID, TypeBound::Copyable);
/// Unspecified opaque error type.
pub const ERROR_TYPE: Type = Type::new_extension(ERROR_CUSTOM_TYPE);

Expand Down
2 changes: 1 addition & 1 deletion hugr-core/src/extension/type_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ mod test {
);
assert_eq!(typ.least_upper_bound(), TypeBound::Copyable);
let typ2 = Type::new_extension(def.instantiate([USIZE_T.into()]).unwrap());
assert_eq!(typ2.least_upper_bound(), TypeBound::Eq);
assert_eq!(typ2.least_upper_bound(), TypeBound::Copyable);

// And some bad arguments...firstly, wrong kind of TypeArg:
assert_eq!(
Expand Down
10 changes: 5 additions & 5 deletions hugr-core/src/hugr/serialize/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,8 +457,8 @@ fn polyfunctype1() -> PolyFuncType {

fn polyfunctype2() -> PolyFuncTypeRV {
let tv0 = TypeRV::new_row_var_use(0, TypeBound::Any);
let tv1 = TypeRV::new_row_var_use(1, TypeBound::Eq);
let params = [TypeBound::Any, TypeBound::Eq].map(TypeParam::new_list);
let tv1 = TypeRV::new_row_var_use(1, TypeBound::Copyable);
let params = [TypeBound::Any, TypeBound::Copyable].map(TypeParam::new_list);
let inputs = vec![
TypeRV::new_function(FuncValueType::new(tv0.clone(), tv1.clone())),
tv0,
Expand All @@ -474,7 +474,7 @@ fn polyfunctype2() -> PolyFuncTypeRV {
#[case(Signature::new_endo(type_row![]).into())]
#[case(polyfunctype1())]
#[case(PolyFuncType::new([TypeParam::String], 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([TypeBound::Copyable.into()], Signature::new_endo(type_row![Type::new_var_use(0, TypeBound::Copyable)])))]
#[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![])))]
#[case(PolyFuncType::new(
Expand All @@ -487,7 +487,7 @@ fn roundtrip_polyfunctype_fixedlen(#[case] poly_func_type: PolyFuncType) {
#[rstest]
#[case(FuncValueType::new_endo(type_row![]).into())]
#[case(PolyFuncTypeRV::new([TypeParam::String], 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([TypeBound::Copyable.into()], FuncValueType::new_endo(type_row![Type::new_var_use(0, TypeBound::Copyable)])))]
#[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![])))]
#[case(PolyFuncTypeRV::new(
Expand All @@ -506,7 +506,7 @@ fn roundtrip_polyfunctype_varlen(#[case] poly_func_type: PolyFuncTypeRV) {
#[case(ops::AliasDecl { name: "aliasdecl".into(), bound: TypeBound::Any})]
#[case(ops::Const::new(Value::false_val()))]
#[case(ops::Const::new(Value::function(crate::builder::test::simple_dfg_hugr()).unwrap()))]
#[case(ops::Input::new(type_row![Type::new_var_use(3,TypeBound::Eq)]))]
#[case(ops::Input::new(type_row![Type::new_var_use(3,TypeBound::Copyable)]))]
#[case(ops::Output::new(vec![Type::new_function(FuncValueType::new_endo(type_row![]))]))]
#[case(ops::Call::try_new(polyfunctype1(), [TypeArg::BoundedNat{n: 1}, TypeArg::Extensions{ es: ExtensionSet::singleton(&PRELUDE_ID)} ], &EMPTY_REG).unwrap())]
#[case(ops::CallIndirect { signature : Signature::new_endo(type_row![BOOL_T]) })]
Expand Down
6 changes: 3 additions & 3 deletions hugr-core/src/ops/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -714,15 +714,15 @@ mod test {
"my_type",
vec![TypeArg::BoundedNat { n: 8 }],
ex_id.clone(),
TypeBound::Eq,
TypeBound::Copyable,
);
let json_const: Value =
CustomSerialized::new(typ_int.clone(), 6.into(), ex_id.clone()).into();
let classic_t = Type::new_extension(typ_int.clone());
assert_matches!(classic_t.least_upper_bound(), TypeBound::Eq);
assert_matches!(classic_t.least_upper_bound(), TypeBound::Copyable);
assert_eq!(json_const.get_type(), classic_t);

let typ_qb = CustomType::new("my_type", vec![], ex_id, TypeBound::Eq);
let typ_qb = CustomType::new("my_type", vec![], ex_id, TypeBound::Copyable);
let t = Type::new_extension(typ_qb.clone());
assert_ne!(json_const.get_type(), t);
}
Expand Down
9 changes: 7 additions & 2 deletions hugr-core/src/std_extensions/arithmetic/int_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ pub const INT_TYPE_ID: TypeName = TypeName::new_inline("int");
/// the operation, the semantic interpretation may be unsigned integer, signed
/// integer or bit string.
pub fn int_custom_type(width_arg: impl Into<TypeArg>) -> CustomType {
CustomType::new(INT_TYPE_ID, [width_arg.into()], EXTENSION_ID, TypeBound::Eq)
CustomType::new(
INT_TYPE_ID,
[width_arg.into()],
EXTENSION_ID,
TypeBound::Copyable,
)
}

/// Integer type of a given bit width (specified by the TypeArg).
Expand Down Expand Up @@ -187,7 +192,7 @@ pub fn extension() -> Extension {
INT_TYPE_ID,
vec![LOG_WIDTH_TYPE_PARAM],
"integral value of a given bit width".to_owned(),
TypeBound::Eq.into(),
TypeBound::Copyable.into(),
)
.unwrap();

Expand Down
4 changes: 2 additions & 2 deletions hugr-core/src/std_extensions/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ fn extension() -> Extension {
PTR_TYPE_ID,
TYPE_PARAMS.into(),
"Standard extension pointer type.".into(),
TypeDefBound::Explicit(TypeBound::Eq),
TypeDefBound::Explicit(TypeBound::Copyable),
)
.unwrap();
PtrOpDef::load_all_ops(&mut extension).unwrap();
Expand All @@ -109,7 +109,7 @@ lazy_static! {
/// integer or bit string.
pub fn ptr_custom_type(ty: impl Into<Type>) -> CustomType {
let ty = ty.into();
CustomType::new(PTR_TYPE_ID, [ty.into()], EXTENSION_ID, TypeBound::Eq)
CustomType::new(PTR_TYPE_ID, [ty.into()], EXTENSION_ID, TypeBound::Copyable)
}

/// Integer type of a given bit width (specified by the TypeArg).
Expand Down
22 changes: 11 additions & 11 deletions hugr-core/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,8 @@ impl EdgeKind {
#[cfg_attr(test, derive(Arbitrary))]
/// Bounds on the valid operations on a type in a HUGR program.
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")]
#[serde(rename = "C", alias = "E")] // alias to read in legacy Eq variants
Copyable,
/// No bound on the type.
#[serde(rename = "A")]
Expand All @@ -105,13 +102,13 @@ impl TypeBound {
/// Report if this bound contains another.
pub const fn contains(&self, other: TypeBound) -> bool {
use TypeBound::*;
matches!((self, other), (Any, _) | (_, Eq) | (Copyable, Copyable))
matches!((self, other), (Any, _) | (_, Copyable))
}
}

/// Calculate the least upper bound for an iterator of bounds
pub(crate) fn least_upper_bound(mut tags: impl Iterator<Item = TypeBound>) -> TypeBound {
tags.fold_while(TypeBound::Eq, |acc, new| {
tags.fold_while(TypeBound::Copyable, |acc, new| {
if acc == TypeBound::Any || new == TypeBound::Any {
Done(TypeBound::Any)
} else {
Expand Down Expand Up @@ -247,7 +244,7 @@ impl<RV: MaybeRV> TypeEnum<RV> {
TypeEnum::Function(_) => TypeBound::Copyable,
TypeEnum::Variable(_, b) => *b,
TypeEnum::RowVar(b) => b.bound(),
TypeEnum::Sum(SumType::Unit { size: _ }) => TypeBound::Eq,
TypeEnum::Sum(SumType::Unit { size: _ }) => TypeBound::Copyable,
TypeEnum::Sum(SumType::General { rows }) => least_upper_bound(
rows.iter()
.flat_map(TypeRowRV::iter)
Expand All @@ -274,7 +271,7 @@ impl<RV: MaybeRV> TypeEnum<RV> {
/// # use hugr::type_row;
///
/// let sum = Type::new_sum([type_row![], type_row![]]);
/// assert_eq!(sum.least_upper_bound(), TypeBound::Eq);
/// assert_eq!(sum.least_upper_bound(), TypeBound::Copyable);
/// ```
///
/// ```
Expand Down Expand Up @@ -316,7 +313,10 @@ impl<RV: MaybeRV> TypeBase<RV> {
/// An empty `TypeRow` or `TypeRowRV`. Provided here for convenience
pub const EMPTY_TYPEROW: TypeRowBase<RV> = TypeRowBase::<RV>::new();
/// Unit type (empty tuple).
pub const UNIT: Self = Self(TypeEnum::Sum(SumType::Unit { size: 1 }), TypeBound::Eq);
pub const UNIT: Self = Self(
TypeEnum::Sum(SumType::Unit { size: 1 }),
TypeBound::Copyable,
);

const EMPTY_TYPEROW_REF: &'static TypeRowBase<RV> = &Self::EMPTY_TYPEROW;

Expand Down Expand Up @@ -364,7 +364,7 @@ impl<RV: MaybeRV> TypeBase<RV> {
/// New UnitSum with empty Tuple variants
pub const fn new_unit_sum(size: u8) -> Self {
// should be the only way to avoid going through SumType::new
Self(TypeEnum::Sum(SumType::new_unary(size)), TypeBound::Eq)
Self(TypeEnum::Sum(SumType::new_unary(size)), TypeBound::Copyable)
}

/// New use (occurrence) of the type variable with specified index.
Expand Down Expand Up @@ -620,7 +620,7 @@ pub(crate) mod test {
"my_extension".try_into().unwrap(),
TypeBound::Copyable,
)),
Type::new_alias(AliasDecl::new("my_alias", TypeBound::Eq)),
Type::new_alias(AliasDecl::new("my_alias", TypeBound::Copyable)),
]);
assert_eq!(
&t.to_string(),
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 @@ -357,7 +357,7 @@ pub(crate) mod test {
fn test_bound_covariance() -> Result<(), SignatureError> {
decl_accepts_rejects_var(
TypeBound::Copyable.into(),
&[TypeBound::Copyable.into(), TypeBound::Eq.into()],
&[TypeBound::Copyable.into()],
&[TypeBound::Any.into()],
)?;

Expand All @@ -366,7 +366,7 @@ pub(crate) mod test {
};
decl_accepts_rejects_var(
list_of_tys(TypeBound::Copyable),
&[list_of_tys(TypeBound::Copyable), list_of_tys(TypeBound::Eq)],
&[list_of_tys(TypeBound::Copyable)],
&[list_of_tys(TypeBound::Any)],
)?;

Expand Down
14 changes: 7 additions & 7 deletions hugr-core/src/types/type_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,21 +450,21 @@ mod test {
check_type_arg(&arg, param)
}
// Simple cases: a TypeArg::Type is a TypeParam::Type but singleton sequences are lists
check(USIZE_T, &TypeBound::Eq.into()).unwrap();
let seq_param = TypeParam::new_list(TypeBound::Eq);
check(USIZE_T, &TypeBound::Copyable.into()).unwrap();
let seq_param = TypeParam::new_list(TypeBound::Copyable);
check(USIZE_T, &seq_param).unwrap_err();
check_seq(&[USIZE_T], &TypeBound::Any.into()).unwrap_err();

// Into a list of type, we can fit a single row var
check(rowvar(0, TypeBound::Eq), &seq_param).unwrap();
check(rowvar(0, TypeBound::Copyable), &seq_param).unwrap();
// or a list of (types or row vars)
check(vec![], &seq_param).unwrap();
check_seq(&[rowvar(0, TypeBound::Eq)], &seq_param).unwrap();
check_seq(&[rowvar(0, TypeBound::Copyable)], &seq_param).unwrap();
check_seq(
&[
rowvar(1, TypeBound::Any),
USIZE_T.into(),
rowvar(0, TypeBound::Eq),
rowvar(0, TypeBound::Copyable),
],
&TypeParam::new_list(TypeBound::Any),
)
Expand All @@ -474,7 +474,7 @@ mod test {
&[
rowvar(1, TypeBound::Any),
USIZE_T.into(),
rowvar(0, TypeBound::Eq),
rowvar(0, TypeBound::Copyable),
],
&seq_param,
)
Expand Down Expand Up @@ -502,7 +502,7 @@ mod test {

// TypeParam::Tuples require a TypeArg::Seq of the same number of elems
let usize_and_ty = TypeParam::Tuple {
params: vec![TypeParam::max_nat(), TypeBound::Eq.into()],
params: vec![TypeParam::max_nat(), TypeBound::Copyable.into()],
};
check(vec![5.into(), USIZE_T.into()], &usize_and_ty).unwrap();
check(vec![USIZE_T.into(), 5.into()], &usize_and_ty).unwrap_err(); // Wrong way around
Expand Down
5 changes: 2 additions & 3 deletions hugr-py/src/hugr/serialization/tys.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,18 +381,17 @@


class TypeBound(Enum):
Eq = "E"
Copyable = "C"
Any = "A"

@staticmethod
def join(*bs: TypeBound) -> TypeBound:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not covered by tests?

Copy link
Member Author

Choose a reason for hiding this comment

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

probably pulled in from guppy, new issue : #1365

"""Computes the least upper bound for a sequence of bounds."""
res = TypeBound.Eq
res = TypeBound.Copyable

Check warning on line 390 in hugr-py/src/hugr/serialization/tys.py

View check run for this annotation

Codecov / codecov/patch

hugr-py/src/hugr/serialization/tys.py#L390

Added line #L390 was not covered by tests
for b in bs:
if b == TypeBound.Any:
return TypeBound.Any
if res == TypeBound.Eq:
if res == TypeBound.Copyable:

Check warning on line 394 in hugr-py/src/hugr/serialization/tys.py

View check run for this annotation

Codecov / codecov/patch

hugr-py/src/hugr/serialization/tys.py#L394

Added line #L394 was not covered by tests
res = b
return res

Expand Down
Loading
Loading