diff --git a/hugr-core/Cargo.toml b/hugr-core/Cargo.toml index e15c1c037..eb4db0dfc 100644 --- a/hugr-core/Cargo.toml +++ b/hugr-core/Cargo.toml @@ -19,6 +19,7 @@ workspace = true [features] declarative = ["serde_yaml"] zstd = ["dep:zstd"] +default = [] [lib] bench = false diff --git a/hugr-core/src/export.rs b/hugr-core/src/export.rs index dff471cc5..1ff2287ca 100644 --- a/hugr-core/src/export.rs +++ b/hugr-core/src/export.rs @@ -863,8 +863,7 @@ impl<'a> Context<'a> { TypeArg::Type { ty } => self.export_type(ty), TypeArg::BoundedNat { n } => self.make_term(model::Literal::Nat(*n).into()), TypeArg::String { arg } => self.make_term(model::Literal::Str(arg.into()).into()), - TypeArg::Sequence { elems } => { - // For now we assume that the sequence is meant to be a list. + TypeArg::List { elems } => { let parts = self.bump.alloc_slice_fill_iter( elems .iter() @@ -872,6 +871,14 @@ impl<'a> Context<'a> { ); self.make_term(table::Term::List(parts)) } + TypeArg::Tuple { elems } => { + let parts = self.bump.alloc_slice_fill_iter( + elems + .iter() + .map(|elem| table::SeqPart::Item(self.export_type_arg(elem))), + ); + self.make_term(table::Term::Tuple(parts)) + } TypeArg::Variable { v } => self.export_type_arg_var(v), } } diff --git a/hugr-core/src/extension/prelude.rs b/hugr-core/src/extension/prelude.rs index 3af70b75b..a76bf65f3 100644 --- a/hugr-core/src/extension/prelude.rs +++ b/hugr-core/src/extension/prelude.rs @@ -678,7 +678,7 @@ impl MakeExtensionOp for MakeTuple { if def != TupleOpDef::MakeTuple { return Err(OpLoadError::NotMember(ext_op.unqualified_id().to_string()))?; } - let [TypeArg::Sequence { elems }] = ext_op.args() else { + let [TypeArg::List { elems }] = ext_op.args() else { return Err(SignatureError::InvalidTypeArgs)?; }; let tys: Result, _> = elems @@ -692,7 +692,7 @@ impl MakeExtensionOp for MakeTuple { } fn type_args(&self) -> Vec { - vec![TypeArg::Sequence { + vec![TypeArg::List { elems: self .0 .iter() @@ -739,7 +739,7 @@ impl MakeExtensionOp for UnpackTuple { if def != TupleOpDef::UnpackTuple { return Err(OpLoadError::NotMember(ext_op.unqualified_id().to_string()))?; } - let [TypeArg::Sequence { elems }] = ext_op.args() else { + let [TypeArg::List { elems }] = ext_op.args() else { return Err(SignatureError::InvalidTypeArgs)?; }; let tys: Result, _> = elems @@ -753,7 +753,7 @@ impl MakeExtensionOp for UnpackTuple { } fn type_args(&self) -> Vec { - vec![TypeArg::Sequence { + vec![TypeArg::List { elems: self .0 .iter() @@ -969,7 +969,7 @@ impl MakeExtensionOp for Barrier { { let _def = BarrierDef::from_def(ext_op.def())?; - let [TypeArg::Sequence { elems }] = ext_op.args() else { + let [TypeArg::List { elems }] = ext_op.args() else { return Err(SignatureError::InvalidTypeArgs)?; }; let tys: Result, _> = elems @@ -985,7 +985,7 @@ impl MakeExtensionOp for Barrier { } fn type_args(&self) -> Vec { - vec![TypeArg::Sequence { + vec![TypeArg::List { elems: self .type_row .iter() @@ -1132,7 +1132,7 @@ mod test { let err = b.add_load_value(error_val); - const TYPE_ARG_NONE: TypeArg = TypeArg::Sequence { elems: vec![] }; + const TYPE_ARG_NONE: TypeArg = TypeArg::List { elems: vec![] }; let op = PRELUDE .instantiate_extension_op(&EXIT_OP_ID, [TYPE_ARG_NONE, TYPE_ARG_NONE]) .unwrap(); @@ -1147,7 +1147,7 @@ mod test { fn test_panic_with_io() { let error_val = ConstError::new(42, "PANIC"); let type_arg_q: TypeArg = TypeArg::Type { ty: qb_t() }; - let type_arg_2q: TypeArg = TypeArg::Sequence { + let type_arg_2q: TypeArg = TypeArg::List { elems: vec![type_arg_q.clone(), type_arg_q], }; let panic_op = PRELUDE diff --git a/hugr-core/src/extension/resolution/types.rs b/hugr-core/src/extension/resolution/types.rs index 531509d6e..bd1694109 100644 --- a/hugr-core/src/extension/resolution/types.rs +++ b/hugr-core/src/extension/resolution/types.rs @@ -217,8 +217,13 @@ pub(super) fn collect_typearg_exts( ) { match arg { TypeArg::Type { ty } => collect_type_exts(ty, used_extensions, missing_extensions), - TypeArg::Sequence { elems } => { - for elem in elems { + TypeArg::List { elems } => { + for elem in elems.iter() { + collect_typearg_exts(elem, used_extensions, missing_extensions); + } + } + TypeArg::Tuple { elems } => { + for elem in elems.iter() { collect_typearg_exts(elem, used_extensions, missing_extensions); } } diff --git a/hugr-core/src/extension/resolution/types_mut.rs b/hugr-core/src/extension/resolution/types_mut.rs index c4093a18c..2840665f5 100644 --- a/hugr-core/src/extension/resolution/types_mut.rs +++ b/hugr-core/src/extension/resolution/types_mut.rs @@ -222,7 +222,12 @@ pub(super) fn resolve_typearg_exts( ) -> Result<(), ExtensionResolutionError> { match arg { TypeArg::Type { ty } => resolve_type_exts(node, ty, extensions, used_extensions)?, - TypeArg::Sequence { elems } => { + TypeArg::List { elems } => { + for elem in elems.iter_mut() { + resolve_typearg_exts(node, elem, extensions, used_extensions)?; + } + } + TypeArg::Tuple { elems } => { for elem in elems.iter_mut() { resolve_typearg_exts(node, elem, extensions, used_extensions)?; } diff --git a/hugr-core/src/hugr/validate/test.rs b/hugr-core/src/hugr/validate/test.rs index 8ee95cde6..08690cb9f 100644 --- a/hugr-core/src/hugr/validate/test.rs +++ b/hugr-core/src/hugr/validate/test.rs @@ -588,8 +588,8 @@ fn instantiate_row_variables() -> Result<(), Box> { Ok(()) } -fn seq1ty(t: TypeRV) -> TypeArg { - TypeArg::Sequence { +fn list1ty(t: TypeRV) -> TypeArg { + TypeArg::List { elems: vec![t.into()], } } @@ -617,7 +617,7 @@ fn row_variables() -> Result<(), Box> { }; let par = e.instantiate_extension_op( "parallel", - [tv.clone(), usize_t().into(), tv.clone(), usize_t().into()].map(seq1ty), + [tv.clone(), usize_t().into(), tv.clone(), usize_t().into()].map(list1ty), )?; let par_func = fb.add_dataflow_op(par, [func_arg, id_usz])?; fb.finish_hugr_with_outputs(par_func.outputs())?; diff --git a/hugr-core/src/import.rs b/hugr-core/src/import.rs index 664f4d3ea..4a7d6080d 100644 --- a/hugr-core/src/import.rs +++ b/hugr-core/src/import.rs @@ -1173,14 +1173,17 @@ impl<'a> Context<'a> { .map(|item| self.import_type_arg(*item)) .collect::>()?; - Ok(TypeArg::Sequence { elems }) + Ok(TypeArg::List { elems }) } table::Term::Tuple { .. } => { - // NOTE: While `TypeArg`s can represent tuples as - // `TypeArg::Sequence`s, this conflates lists and tuples. To - // avoid ambiguity we therefore report an error here for now. - Err(error_unsupported!("tuples as `TypeArg`")) + let elems = self + .import_closed_list(term_id)? + .iter() + .map(|item| self.import_type_arg(*item)) + .collect::>()?; + + Ok(TypeArg::Tuple { elems }) } table::Term::Literal(model::Literal::Str(value)) => Ok(TypeArg::String { diff --git a/hugr-core/src/ops/controlflow.rs b/hugr-core/src/ops/controlflow.rs index 9c05740a5..0c5d42d9b 100644 --- a/hugr-core/src/ops/controlflow.rs +++ b/hugr-core/src/ops/controlflow.rs @@ -378,7 +378,7 @@ mod test { outputs: vec![usize_t(), tv1].into(), }; let cond2 = cond.substitute(&Substitution::new(&[ - TypeArg::Sequence { + TypeArg::List { elems: vec![usize_t().into(); 3], }, qb_t().into(), diff --git a/hugr-core/src/std_extensions/collections/array/array_scan.rs b/hugr-core/src/std_extensions/collections/array/array_scan.rs index 2dc5d2f73..b29996bfe 100644 --- a/hugr-core/src/std_extensions/collections/array/array_scan.rs +++ b/hugr-core/src/std_extensions/collections/array/array_scan.rs @@ -188,7 +188,7 @@ impl MakeExtensionOp for GenericArrayScan { TypeArg::BoundedNat { n: self.size }, self.src_ty.clone().into(), self.tgt_ty.clone().into(), - TypeArg::Sequence { + TypeArg::List { elems: self.acc_tys.clone().into_iter().map_into().collect(), }, ] @@ -218,7 +218,7 @@ impl HasConcrete for GenericArrayScanDef { TypeArg::BoundedNat { n }, TypeArg::Type { ty: src_ty }, TypeArg::Type { ty: tgt_ty }, - TypeArg::Sequence { elems: acc_tys }, + TypeArg::List { elems: acc_tys }, ] => { let acc_tys: Result<_, OpLoadError> = acc_tys .iter() diff --git a/hugr-core/src/types.rs b/hugr-core/src/types.rs index f5b3db39b..684854dae 100644 --- a/hugr-core/src/types.rs +++ b/hugr-core/src/types.rs @@ -741,7 +741,7 @@ impl<'a> Substitution<'a> { .expect("Undeclared type variable - call validate() ?"); debug_assert!(check_type_arg(arg, &TypeParam::new_list(bound)).is_ok()); match arg { - TypeArg::Sequence { elems } => elems + TypeArg::List { elems } => elems .iter() .map(|ta| { match ta { @@ -1003,7 +1003,7 @@ pub(crate) mod test { let coln = e.get_type(&COLN).unwrap(); let c_of_cpy = coln - .instantiate([TypeArg::Sequence { + .instantiate([TypeArg::List { elems: vec![Type::from(cpy.clone()).into()], }]) .unwrap(); @@ -1018,7 +1018,7 @@ pub(crate) mod test { ); let mut t = Type::new_extension( - coln.instantiate([TypeArg::Sequence { + coln.instantiate([TypeArg::List { elems: vec![mk_opt(Type::from(cpy.clone())).into()], }]) .unwrap(), @@ -1037,7 +1037,7 @@ pub(crate) mod test { (ct == &c_of_cpy).then_some(usize_t()) }); let mut t = Type::new_extension( - coln.instantiate([TypeArg::Sequence { + coln.instantiate([TypeArg::List { elems: vec![Type::from(c_of_cpy.clone()).into(); 2], }]) .unwrap(), @@ -1046,7 +1046,7 @@ pub(crate) mod test { assert_eq!( t, Type::new_extension( - coln.instantiate([TypeArg::Sequence { + coln.instantiate([TypeArg::List { elems: vec![usize_t().into(); 2] }]) .unwrap() diff --git a/hugr-core/src/types/poly_func.rs b/hugr-core/src/types/poly_func.rs index 8121741bf..20f48907b 100644 --- a/hugr-core/src/types/poly_func.rs +++ b/hugr-core/src/types/poly_func.rs @@ -436,14 +436,12 @@ pub(crate) mod test { } pf.instantiate(&[TypeArg::Type { ty: usize_t() }]) .unwrap_err(); - pf.instantiate(&[TypeArg::Sequence { - elems: vec![usize_t().into(), TypeArg::Sequence { elems: seq2() }], + pf.instantiate(&[TypeArg::List { + elems: vec![usize_t().into(), TypeArg::List { elems: seq2() }], }]) .unwrap_err(); - let t2 = pf - .instantiate(&[TypeArg::Sequence { elems: seq2() }]) - .unwrap(); + let t2 = pf.instantiate(&[TypeArg::List { elems: seq2() }]).unwrap(); assert_eq!( t2, Signature::new( @@ -471,7 +469,7 @@ pub(crate) mod test { let inner3 = Type::new_function(Signature::new_endo(vec![usize_t(), bool_t(), usize_t()])); let t3 = pf - .instantiate(&[TypeArg::Sequence { + .instantiate(&[TypeArg::List { elems: vec![usize_t().into(), bool_t().into(), usize_t().into()], }]) .unwrap(); diff --git a/hugr-core/src/types/type_param.rs b/hugr-core/src/types/type_param.rs index 0b6d19fa7..39aeb0e4f 100644 --- a/hugr-core/src/types/type_param.rs +++ b/hugr-core/src/types/type_param.rs @@ -171,14 +171,22 @@ pub enum TypeArg { /// The string value for the parameter. arg: String, }, - /// Instance of [`TypeParam::List`] or [`TypeParam::Tuple`], defined by a - /// sequence of elements. + /// Instance of [TypeParam::List] defined by a sequence of elements of the same type. + #[display("[{}]", { + use itertools::Itertools as _; + elems.iter().map(|t|t.to_string()).join(",") + })] + List { + /// List of elements + elems: Vec, + }, + /// Instance of [TypeParam::Tuple] defined by a sequence of elements of varying type. #[display("({})", { use itertools::Itertools as _; elems.iter().map(std::string::ToString::to_string).join(",") })] - Sequence { - /// List of element types + Tuple { + /// List of elements elems: Vec, }, /// Variable (used in type schemes or inside polymorphic functions), @@ -223,7 +231,7 @@ impl From<&str> for TypeArg { impl From> for TypeArg { fn from(elems: Vec) -> Self { - Self::Sequence { elems } + Self::List { elems } } } @@ -294,7 +302,11 @@ impl TypeArg { match self { TypeArg::Type { ty } => ty.validate(var_decls), TypeArg::BoundedNat { .. } | TypeArg::String { .. } => Ok(()), - TypeArg::Sequence { elems } => elems.iter().try_for_each(|a| a.validate(var_decls)), + TypeArg::List { elems } => { + // TODO: Full validation would check that the type of the elements agrees + elems.iter().try_for_each(|a| a.validate(var_decls)) + } + TypeArg::Tuple { elems } => elems.iter().try_for_each(|a| a.validate(var_decls)), TypeArg::Variable { v: TypeArgVariable { idx, cached_decl }, } => { @@ -315,7 +327,7 @@ impl TypeArg { ty.substitute1(t).into() } TypeArg::BoundedNat { .. } | TypeArg::String { .. } => self.clone(), // We do not allow variables as bounds on BoundedNat's - TypeArg::Sequence { elems } => { + TypeArg::List { elems } => { let mut are_types = elems.iter().map(|ta| match ta { TypeArg::Type { .. } => true, TypeArg::Variable { v } => v.bound_if_row_var().is_some(), @@ -329,7 +341,7 @@ impl TypeArg { .iter() .flat_map(|ta| match ta.substitute(t) { ty @ TypeArg::Type { .. } => vec![ty], - TypeArg::Sequence { elems } => elems, + TypeArg::List { elems } => elems, _ => panic!("Expected Type or row of Types"), }) .collect() @@ -339,8 +351,11 @@ impl TypeArg { elems.iter().map(|ta| ta.substitute(t)).collect() } }; - TypeArg::Sequence { elems } + TypeArg::List { elems } } + TypeArg::Tuple { elems } => TypeArg::Tuple { + elems: elems.iter().map(|elem| elem.substitute(t)).collect(), + }, TypeArg::Variable { v: TypeArgVariable { idx, cached_decl }, } => t.apply_var(*idx, cached_decl), @@ -352,7 +367,8 @@ impl Transformable for TypeArg { fn transform(&mut self, tr: &T) -> Result { match self { TypeArg::Type { ty } => ty.transform(tr), - TypeArg::Sequence { elems } => elems.transform(tr), + TypeArg::List { elems } => elems.transform(tr), + TypeArg::Tuple { elems } => elems.transform(tr), TypeArg::BoundedNat { .. } | TypeArg::String { .. } | TypeArg::Variable { .. } => { Ok(false) } @@ -394,7 +410,7 @@ pub fn check_type_arg(arg: &TypeArg, param: &TypeParam) -> Result<(), TypeArgErr { Ok(()) } - (TypeArg::Sequence { elems }, TypeParam::List { param }) => { + (TypeArg::List { elems }, TypeParam::List { param }) => { elems.iter().try_for_each(|arg| { // Also allow elements that are RowVars if fitting into a List of Types if let (TypeArg::Variable { v }, TypeParam::Type { b: param_bound }) = @@ -409,15 +425,15 @@ pub fn check_type_arg(arg: &TypeArg, param: &TypeParam) -> Result<(), TypeArgErr check_type_arg(arg, param) }) } - (TypeArg::Sequence { elems: items }, TypeParam::Tuple { params: types }) => { - if items.len() == types.len() { - items - .iter() - .zip(types.iter()) - .try_for_each(|(arg, param)| check_type_arg(arg, param)) - } else { - Err(TypeArgError::WrongNumberTuple(items.len(), types.len())) + (TypeArg::Tuple { elems: items }, TypeParam::Tuple { params: types }) => { + if items.len() != types.len() { + return Err(TypeArgError::WrongNumberTuple(items.len(), types.len())); } + + items + .iter() + .zip(types.iter()) + .try_for_each(|(arg, param)| check_type_arg(arg, param)) } (TypeArg::BoundedNat { n: val }, TypeParam::BoundedNat { bound }) if bound.valid_value(*val) => @@ -545,12 +561,24 @@ mod test { ) .unwrap_err(); - // TypeParam::Tuples require a TypeArg::Seq of the same number of elems + // TypeParam::Tuples require a TypeArg::Tuple of the same number of elems let usize_and_ty = TypeParam::Tuple { 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 + check( + TypeArg::Tuple { + elems: vec![5.into(), usize_t().into()], + }, + &usize_and_ty, + ) + .unwrap(); + check( + TypeArg::Tuple { + elems: vec![usize_t().into(), 5.into()], + }, + &usize_and_ty, + ) + .unwrap_err(); // Wrong way around let two_types = TypeParam::Tuple { params: vec![TypeBound::Any.into(), TypeBound::Any.into()], }; @@ -568,7 +596,7 @@ mod test { // Now say a row variable referring to *that* row was used // to instantiate an outer "row parameter" (list of type). let outer_param = TypeParam::new_list(TypeBound::Any); - let outer_arg = TypeArg::Sequence { + let outer_arg = TypeArg::List { elems: vec![ TypeRV::new_row_var_use(0, TypeBound::Copyable).into(), usize_t().into(), @@ -591,7 +619,7 @@ mod test { let outer_param = TypeParam::new_list(TypeParam::new_list(TypeBound::Any)); let row_var_decl = TypeParam::new_list(TypeBound::Copyable); let row_var_use = TypeArg::new_var_use(0, row_var_decl.clone()); - let good_arg = TypeArg::Sequence { + let good_arg = TypeArg::List { elems: vec![ // The row variables here refer to `row_var_decl` above vec![usize_t().into()].into(), @@ -602,12 +630,12 @@ mod test { check_type_arg(&good_arg, &outer_param).unwrap(); // Outer list cannot include single types: - let TypeArg::Sequence { mut elems } = good_arg.clone() else { + let TypeArg::List { mut elems } = good_arg.clone() else { panic!() }; elems.push(usize_t().into()); assert_eq!( - check_type_arg(&TypeArg::Sequence { elems }, &outer_param), + check_type_arg(&TypeArg::List { elems }, &outer_param), Err(TypeArgError::TypeMismatch { arg: usize_t().into(), // The error reports the type expected for each element of the list: @@ -622,7 +650,7 @@ mod test { check_type_arg(&subst_arg, &outer_param).unwrap(); // invariance of substitution assert_eq!( subst_arg, - TypeArg::Sequence { + TypeArg::List { elems: vec![ vec![usize_t().into()].into(), row_var_arg, @@ -701,7 +729,7 @@ mod test { if !depth.leaf() { // We descend here because this constructor contains TypeArg> strat = strat.or(vec(any_with::(depth.descend()), 0..3) - .prop_map(|elems| Self::Sequence { elems }) + .prop_map(|elems| Self::List { elems }) .boxed()); } strat.boxed() diff --git a/hugr-llvm/src/extension/prelude.rs b/hugr-llvm/src/extension/prelude.rs index 62a00527c..f8f7d5542 100644 --- a/hugr-llvm/src/extension/prelude.rs +++ b/hugr-llvm/src/extension/prelude.rs @@ -560,7 +560,7 @@ mod test { fn prelude_panic(prelude_llvm_ctx: TestContext) { let error_val = ConstError::new(42, "PANIC"); let type_arg_q: TypeArg = TypeArg::Type { ty: qb_t() }; - let type_arg_2q: TypeArg = TypeArg::Sequence { + let type_arg_2q: TypeArg = TypeArg::List { elems: vec![type_arg_q.clone(), type_arg_q], }; let panic_op = PRELUDE @@ -588,7 +588,7 @@ mod test { fn prelude_exit(prelude_llvm_ctx: TestContext) { let error_val = ConstError::new(42, "EXIT"); let type_arg_q: TypeArg = TypeArg::Type { ty: qb_t() }; - let type_arg_2q: TypeArg = TypeArg::Sequence { + let type_arg_2q: TypeArg = TypeArg::List { elems: vec![type_arg_q.clone(), type_arg_q], }; let exit_op = PRELUDE diff --git a/hugr-passes/src/monomorphize.rs b/hugr-passes/src/monomorphize.rs index 2a97f7524..0cdda3aa9 100644 --- a/hugr-passes/src/monomorphize.rs +++ b/hugr-passes/src/monomorphize.rs @@ -231,9 +231,10 @@ impl> ComposablePass for MonomorphizePass { } } -struct TypeArgsList<'a>(&'a [TypeArg]); +/// Helper to create mangled representations of lists of [TypeArg]s. +struct TypeArgsSeq<'a>(&'a [TypeArg]); -impl std::fmt::Display for TypeArgsList<'_> { +impl std::fmt::Display for TypeArgsSeq<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for arg in self.0 { f.write_char('$')?; @@ -252,7 +253,8 @@ fn write_type_arg_str(arg: &TypeArg, f: &mut std::fmt::Formatter<'_>) -> std::fm TypeArg::Type { ty } => f.write_fmt(format_args!("t({})", escape_dollar(ty.to_string()))), TypeArg::BoundedNat { n } => f.write_fmt(format_args!("n({n})")), TypeArg::String { arg } => f.write_fmt(format_args!("s({})", escape_dollar(arg))), - TypeArg::Sequence { elems } => f.write_fmt(format_args!("seq({})", TypeArgsList(elems))), + TypeArg::List { elems } => f.write_fmt(format_args!("list({})", TypeArgsSeq(elems))), + TypeArg::Tuple { elems } => f.write_fmt(format_args!("tuple({})", TypeArgsSeq(elems))), // We are monomorphizing. We will never monomorphize to a signature // containing a variable. TypeArg::Variable { .. } => panic!("type_arg_str variable: {arg}"), @@ -275,7 +277,7 @@ fn write_type_arg_str(arg: &TypeArg, f: &mut std::fmt::Formatter<'_>) -> std::fm /// is used as "t({arg})" for the string representation of that arg. pub fn mangle_name(name: &str, type_args: impl AsRef<[TypeArg]>) -> String { let name = escape_dollar(name); - format!("${name}${}", TypeArgsList(type_args.as_ref())) + format!("${name}${}", TypeArgsSeq(type_args.as_ref())) } fn mangle_inner_func(outer_name: &str, inner_name: &str) -> String { @@ -657,7 +659,8 @@ mod test { #[case::type_int(vec![INT_TYPES[2].clone().into()], "$foo$$t(int(2))")] #[case::string(vec!["arg".into()], "$foo$$s(arg)")] #[case::dollar_string(vec!["$arg".into()], "$foo$$s(\\$arg)")] - #[case::sequence(vec![vec![0.into(), Type::UNIT.into()].into()], "$foo$$seq($n(0)$t(Unit))")] + #[case::sequence(vec![vec![0.into(), Type::UNIT.into()].into()], "$foo$$list($n(0)$t(Unit))")] + #[case::sequence(vec![TypeArg::Tuple { elems: vec![0.into(), Type::UNIT.into()] }], "$foo$$tuple($n(0)$t(Unit))")] #[should_panic] #[case::typeargvariable(vec![TypeArg::new_var_use(1, TypeParam::String)], "$foo$$v(1)")] diff --git a/hugr-py/src/hugr/_serialization/tys.py b/hugr-py/src/hugr/_serialization/tys.py index c00a73375..05c648187 100644 --- a/hugr-py/src/hugr/_serialization/tys.py +++ b/hugr-py/src/hugr/_serialization/tys.py @@ -158,12 +158,20 @@ def deserialize(self) -> tys.StringArg: return tys.StringArg(value=self.arg) -class SequenceArg(BaseTypeArg): - tya: Literal["Sequence"] = "Sequence" +class ListArg(BaseTypeArg): + tya: Literal["List"] = "List" elems: list[TypeArg] - def deserialize(self) -> tys.SequenceArg: - return tys.SequenceArg(elems=deser_it(self.elems)) + def deserialize(self) -> tys.ListArg: + return tys.ListArg(elems=deser_it(self.elems)) + + +class TupleArg(BaseTypeArg): + tya: Literal["Tuple"] = "Tuple" + elems: list[TypeArg] + + def deserialize(self) -> tys.TupleArg: + return tys.TupleArg(elems=deser_it(self.elems)) class VariableArg(BaseTypeArg): @@ -179,7 +187,7 @@ class TypeArg(RootModel): """A type argument.""" root: Annotated[ - TypeTypeArg | BoundedNatArg | StringArg | SequenceArg | VariableArg, + TypeTypeArg | BoundedNatArg | StringArg | ListArg | TupleArg | VariableArg, WrapValidator(_json_custom_error_validator), ] = Field(discriminator="tya") diff --git a/hugr-py/src/hugr/ops.py b/hugr-py/src/hugr/ops.py index fdcdd8908..1d11a3cfe 100644 --- a/hugr-py/src/hugr/ops.py +++ b/hugr-py/src/hugr/ops.py @@ -534,7 +534,7 @@ def cached_signature(self) -> tys.FunctionType | None: ) def type_args(self) -> list[tys.TypeArg]: - return [tys.SequenceArg([t.type_arg() for t in self.types])] + return [tys.ListArg([t.type_arg() for t in self.types])] def __call__(self, *elements: ComWire) -> Command: return super().__call__(*elements) @@ -576,7 +576,7 @@ def cached_signature(self) -> tys.FunctionType | None: ) def type_args(self) -> list[tys.TypeArg]: - return [tys.SequenceArg([t.type_arg() for t in self.types])] + return [tys.ListArg([t.type_arg() for t in self.types])] @property def num_out(self) -> int: diff --git a/hugr-py/src/hugr/tys.py b/hugr-py/src/hugr/tys.py index 8411f19bf..743d61530 100644 --- a/hugr-py/src/hugr/tys.py +++ b/hugr-py/src/hugr/tys.py @@ -245,26 +245,43 @@ def to_model(self) -> model.Term: @dataclass(frozen=True) -class SequenceArg(TypeArg): - """Sequence of type arguments, for a :class:`ListParam` or :class:`TupleParam`.""" +class ListArg(TypeArg): + """Sequence of type arguments for a :class:`ListParam`.""" elems: list[TypeArg] - def _to_serial(self) -> stys.SequenceArg: - return stys.SequenceArg(elems=ser_it(self.elems)) + def _to_serial(self) -> stys.ListArg: + return stys.ListArg(elems=ser_it(self.elems)) def resolve(self, registry: ext.ExtensionRegistry) -> TypeArg: - return SequenceArg([arg.resolve(registry) for arg in self.elems]) + return ListArg([arg.resolve(registry) for arg in self.elems]) def __str__(self) -> str: - return f"({comma_sep_str(self.elems)})" + return f"[{comma_sep_str(self.elems)}]" def to_model(self) -> model.Term: - # TODO: We should separate lists and tuples. - # For now we assume that this is a list. return model.List([elem.to_model() for elem in self.elems]) +@dataclass(frozen=True) +class TupleArg(TypeArg): + """Sequence of type arguments for a :class:`TupleParam`.""" + + elems: list[TypeArg] + + def _to_serial(self) -> stys.TupleArg: + return stys.TupleArg(elems=ser_it(self.elems)) + + def resolve(self, registry: ext.ExtensionRegistry) -> TypeArg: + return TupleArg([arg.resolve(registry) for arg in self.elems]) + + def __str__(self) -> str: + return f"({comma_sep_str(self.elems)})" + + def to_model(self) -> model.Term: + return model.Tuple([elem.to_model() for elem in self.elems]) + + @dataclass(frozen=True) class VariableArg(TypeArg): """A type argument variable.""" diff --git a/hugr-py/tests/test_tys.py b/hugr-py/tests/test_tys.py index 8f2c9de0c..329dd1227 100644 --- a/hugr-py/tests/test_tys.py +++ b/hugr-py/tests/test_tys.py @@ -17,16 +17,17 @@ Either, ExtType, FunctionType, + ListArg, ListParam, Option, PolyFuncType, Qubit, RowVariable, - SequenceArg, StringArg, StringParam, Sum, Tuple, + TupleArg, TupleParam, Type, TypeArg, @@ -107,7 +108,11 @@ def test_params_str(param: TypeParam, string: str): (BoundedNatArg(3), "3"), (StringArg("hello"), '"hello"'), ( - SequenceArg([TypeTypeArg(Qubit), BoundedNatArg(3)]), + ListArg([TypeTypeArg(Qubit), BoundedNatArg(3)]), + "[Type(Qubit), 3]", + ), + ( + TupleArg([TypeTypeArg(Qubit), BoundedNatArg(3)]), "(Type(Qubit), 3)", ), (VariableArg(2, StringParam()), "$2"), diff --git a/specification/schema/hugr_schema_live.json b/specification/schema/hugr_schema_live.json index e83f15d7e..364c52098 100644 --- a/specification/schema/hugr_schema_live.json +++ b/specification/schema/hugr_schema_live.json @@ -760,6 +760,29 @@ "title": "Input", "type": "object" }, + "ListArg": { + "additionalProperties": true, + "properties": { + "tya": { + "const": "List", + "default": "List", + "title": "Tya", + "type": "string" + }, + "elems": { + "items": { + "$ref": "#/$defs/TypeArg" + }, + "title": "Elems", + "type": "array" + } + }, + "required": [ + "elems" + ], + "title": "ListArg", + "type": "object" + }, "ListParam": { "additionalProperties": true, "properties": { @@ -1170,29 +1193,6 @@ "title": "RowVar", "type": "object" }, - "SequenceArg": { - "additionalProperties": true, - "properties": { - "tya": { - "const": "Sequence", - "default": "Sequence", - "title": "Tya", - "type": "string" - }, - "elems": { - "items": { - "$ref": "#/$defs/TypeArg" - }, - "title": "Elems", - "type": "array" - } - }, - "required": [ - "elems" - ], - "title": "SequenceArg", - "type": "object" - }, "SerialHugr": { "additionalProperties": true, "description": "A serializable representation of a Hugr.", @@ -1482,6 +1482,29 @@ "title": "TailLoop", "type": "object" }, + "TupleArg": { + "additionalProperties": true, + "properties": { + "tya": { + "const": "Tuple", + "default": "Tuple", + "title": "Tya", + "type": "string" + }, + "elems": { + "items": { + "$ref": "#/$defs/TypeArg" + }, + "title": "Elems", + "type": "array" + } + }, + "required": [ + "elems" + ], + "title": "TupleArg", + "type": "object" + }, "TupleParam": { "additionalProperties": true, "properties": { @@ -1580,8 +1603,9 @@ "discriminator": { "mapping": { "BoundedNat": "#/$defs/BoundedNatArg", - "Sequence": "#/$defs/SequenceArg", + "List": "#/$defs/ListArg", "String": "#/$defs/StringArg", + "Tuple": "#/$defs/TupleArg", "Type": "#/$defs/TypeTypeArg", "Variable": "#/$defs/VariableArg" }, @@ -1598,7 +1622,10 @@ "$ref": "#/$defs/StringArg" }, { - "$ref": "#/$defs/SequenceArg" + "$ref": "#/$defs/ListArg" + }, + { + "$ref": "#/$defs/TupleArg" }, { "$ref": "#/$defs/VariableArg" diff --git a/specification/schema/hugr_schema_strict_live.json b/specification/schema/hugr_schema_strict_live.json index a74f238cb..51b5f4e22 100644 --- a/specification/schema/hugr_schema_strict_live.json +++ b/specification/schema/hugr_schema_strict_live.json @@ -760,6 +760,29 @@ "title": "Input", "type": "object" }, + "ListArg": { + "additionalProperties": false, + "properties": { + "tya": { + "const": "List", + "default": "List", + "title": "Tya", + "type": "string" + }, + "elems": { + "items": { + "$ref": "#/$defs/TypeArg" + }, + "title": "Elems", + "type": "array" + } + }, + "required": [ + "elems" + ], + "title": "ListArg", + "type": "object" + }, "ListParam": { "additionalProperties": false, "properties": { @@ -1170,29 +1193,6 @@ "title": "RowVar", "type": "object" }, - "SequenceArg": { - "additionalProperties": false, - "properties": { - "tya": { - "const": "Sequence", - "default": "Sequence", - "title": "Tya", - "type": "string" - }, - "elems": { - "items": { - "$ref": "#/$defs/TypeArg" - }, - "title": "Elems", - "type": "array" - } - }, - "required": [ - "elems" - ], - "title": "SequenceArg", - "type": "object" - }, "SerialHugr": { "additionalProperties": false, "description": "A serializable representation of a Hugr.", @@ -1482,6 +1482,29 @@ "title": "TailLoop", "type": "object" }, + "TupleArg": { + "additionalProperties": false, + "properties": { + "tya": { + "const": "Tuple", + "default": "Tuple", + "title": "Tya", + "type": "string" + }, + "elems": { + "items": { + "$ref": "#/$defs/TypeArg" + }, + "title": "Elems", + "type": "array" + } + }, + "required": [ + "elems" + ], + "title": "TupleArg", + "type": "object" + }, "TupleParam": { "additionalProperties": false, "properties": { @@ -1580,8 +1603,9 @@ "discriminator": { "mapping": { "BoundedNat": "#/$defs/BoundedNatArg", - "Sequence": "#/$defs/SequenceArg", + "List": "#/$defs/ListArg", "String": "#/$defs/StringArg", + "Tuple": "#/$defs/TupleArg", "Type": "#/$defs/TypeTypeArg", "Variable": "#/$defs/VariableArg" }, @@ -1598,7 +1622,10 @@ "$ref": "#/$defs/StringArg" }, { - "$ref": "#/$defs/SequenceArg" + "$ref": "#/$defs/ListArg" + }, + { + "$ref": "#/$defs/TupleArg" }, { "$ref": "#/$defs/VariableArg" diff --git a/specification/schema/testing_hugr_schema_live.json b/specification/schema/testing_hugr_schema_live.json index 86e7cf775..d6aaa8b24 100644 --- a/specification/schema/testing_hugr_schema_live.json +++ b/specification/schema/testing_hugr_schema_live.json @@ -760,6 +760,29 @@ "title": "Input", "type": "object" }, + "ListArg": { + "additionalProperties": true, + "properties": { + "tya": { + "const": "List", + "default": "List", + "title": "Tya", + "type": "string" + }, + "elems": { + "items": { + "$ref": "#/$defs/TypeArg" + }, + "title": "Elems", + "type": "array" + } + }, + "required": [ + "elems" + ], + "title": "ListArg", + "type": "object" + }, "ListParam": { "additionalProperties": true, "properties": { @@ -1170,29 +1193,6 @@ "title": "RowVar", "type": "object" }, - "SequenceArg": { - "additionalProperties": true, - "properties": { - "tya": { - "const": "Sequence", - "default": "Sequence", - "title": "Tya", - "type": "string" - }, - "elems": { - "items": { - "$ref": "#/$defs/TypeArg" - }, - "title": "Elems", - "type": "array" - } - }, - "required": [ - "elems" - ], - "title": "SequenceArg", - "type": "object" - }, "SerialHugr": { "description": "A serializable representation of a Hugr.", "properties": { @@ -1560,6 +1560,29 @@ "title": "TestingHugr", "type": "object" }, + "TupleArg": { + "additionalProperties": true, + "properties": { + "tya": { + "const": "Tuple", + "default": "Tuple", + "title": "Tya", + "type": "string" + }, + "elems": { + "items": { + "$ref": "#/$defs/TypeArg" + }, + "title": "Elems", + "type": "array" + } + }, + "required": [ + "elems" + ], + "title": "TupleArg", + "type": "object" + }, "TupleParam": { "additionalProperties": true, "properties": { @@ -1658,8 +1681,9 @@ "discriminator": { "mapping": { "BoundedNat": "#/$defs/BoundedNatArg", - "Sequence": "#/$defs/SequenceArg", + "List": "#/$defs/ListArg", "String": "#/$defs/StringArg", + "Tuple": "#/$defs/TupleArg", "Type": "#/$defs/TypeTypeArg", "Variable": "#/$defs/VariableArg" }, @@ -1676,7 +1700,10 @@ "$ref": "#/$defs/StringArg" }, { - "$ref": "#/$defs/SequenceArg" + "$ref": "#/$defs/ListArg" + }, + { + "$ref": "#/$defs/TupleArg" }, { "$ref": "#/$defs/VariableArg" diff --git a/specification/schema/testing_hugr_schema_strict_live.json b/specification/schema/testing_hugr_schema_strict_live.json index 28201a79e..0b8023ea8 100644 --- a/specification/schema/testing_hugr_schema_strict_live.json +++ b/specification/schema/testing_hugr_schema_strict_live.json @@ -760,6 +760,29 @@ "title": "Input", "type": "object" }, + "ListArg": { + "additionalProperties": false, + "properties": { + "tya": { + "const": "List", + "default": "List", + "title": "Tya", + "type": "string" + }, + "elems": { + "items": { + "$ref": "#/$defs/TypeArg" + }, + "title": "Elems", + "type": "array" + } + }, + "required": [ + "elems" + ], + "title": "ListArg", + "type": "object" + }, "ListParam": { "additionalProperties": false, "properties": { @@ -1170,29 +1193,6 @@ "title": "RowVar", "type": "object" }, - "SequenceArg": { - "additionalProperties": false, - "properties": { - "tya": { - "const": "Sequence", - "default": "Sequence", - "title": "Tya", - "type": "string" - }, - "elems": { - "items": { - "$ref": "#/$defs/TypeArg" - }, - "title": "Elems", - "type": "array" - } - }, - "required": [ - "elems" - ], - "title": "SequenceArg", - "type": "object" - }, "SerialHugr": { "description": "A serializable representation of a Hugr.", "properties": { @@ -1560,6 +1560,29 @@ "title": "TestingHugr", "type": "object" }, + "TupleArg": { + "additionalProperties": false, + "properties": { + "tya": { + "const": "Tuple", + "default": "Tuple", + "title": "Tya", + "type": "string" + }, + "elems": { + "items": { + "$ref": "#/$defs/TypeArg" + }, + "title": "Elems", + "type": "array" + } + }, + "required": [ + "elems" + ], + "title": "TupleArg", + "type": "object" + }, "TupleParam": { "additionalProperties": false, "properties": { @@ -1658,8 +1681,9 @@ "discriminator": { "mapping": { "BoundedNat": "#/$defs/BoundedNatArg", - "Sequence": "#/$defs/SequenceArg", + "List": "#/$defs/ListArg", "String": "#/$defs/StringArg", + "Tuple": "#/$defs/TupleArg", "Type": "#/$defs/TypeTypeArg", "Variable": "#/$defs/VariableArg" }, @@ -1676,7 +1700,10 @@ "$ref": "#/$defs/StringArg" }, { - "$ref": "#/$defs/SequenceArg" + "$ref": "#/$defs/ListArg" + }, + { + "$ref": "#/$defs/TupleArg" }, { "$ref": "#/$defs/VariableArg"