From 85b7af17142fa60439128d6bb46d27207028bd8f Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 29 Nov 2024 09:15:22 +0000 Subject: [PATCH 1/2] Add {ExtensionSet,Type,TypeArg}::contains_vars --- hugr-core/src/extension.rs | 4 ++++ hugr-core/src/types.rs | 22 ++++++++++++++++++++++ hugr-core/src/types/type_param.rs | 10 ++++++++++ 3 files changed, 36 insertions(+) diff --git a/hugr-core/src/extension.rs b/hugr-core/src/extension.rs index 6d30d635e..f496fffb9 100644 --- a/hugr-core/src/extension.rs +++ b/hugr-core/src/extension.rs @@ -681,6 +681,10 @@ impl ExtensionSet { }, })) } + + pub(crate) fn contains_vars(&self) -> bool { + self.0.iter().any(|id| as_typevar(id).is_some()) + } } impl From for ExtensionSet { diff --git a/hugr-core/src/types.rs b/hugr-core/src/types.rs index c61149bff..3bc373a67 100644 --- a/hugr-core/src/types.rs +++ b/hugr-core/src/types.rs @@ -455,6 +455,28 @@ impl TypeBase { } } } + + pub(crate) fn contains_vars(&self) -> bool { + match self.as_type_enum() { + TypeEnum::Extension(custom_type) => { + custom_type.args().iter().any(TypeArg::contains_vars) + } + TypeEnum::Alias(_) => false, // Any unresolved/undefined AliasDecl must be at top level in Module so no vars in scope + TypeEnum::Function(ft) => { + ft.input.iter().any(TypeRV::contains_vars) + || ft.output.iter().any(TypeRV::contains_vars) + || ft.extension_reqs.contains_vars() + } + TypeEnum::Variable(_, _) | TypeEnum::RowVar(_) => true, + TypeEnum::Sum(sum_type) => (0..sum_type.num_variants()).any(|i| { + sum_type + .get_variant(i) + .unwrap() + .iter() + .any(TypeRV::contains_vars) + }), + } + } } impl Type { diff --git a/hugr-core/src/types/type_param.rs b/hugr-core/src/types/type_param.rs index 4ffeaecf4..2f79e9418 100644 --- a/hugr-core/src/types/type_param.rs +++ b/hugr-core/src/types/type_param.rs @@ -321,6 +321,16 @@ impl TypeArg { } => t.apply_var(*idx, cached_decl), } } + + pub(crate) fn contains_vars(&self) -> bool { + match self { + TypeArg::Type { ty } => ty.contains_vars(), + TypeArg::BoundedNat { .. } | TypeArg::String { .. } => false, + TypeArg::Sequence { elems } => elems.iter().any(TypeArg::contains_vars), + TypeArg::Extensions { es } => es.contains_vars(), + TypeArg::Variable { .. } => true, + } + } } impl TypeArgVariable { From 82e27ea633593a22b0c87e7e708e3e9104792597 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Fri, 29 Nov 2024 09:15:46 +0000 Subject: [PATCH 2/2] Add ListOp::new --- hugr-core/src/std_extensions/collections.rs | 6 ++++++ .../std_extensions/collections/list_fold.rs | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/hugr-core/src/std_extensions/collections.rs b/hugr-core/src/std_extensions/collections.rs index 2f416c92b..042f82a67 100644 --- a/hugr-core/src/std_extensions/collections.rs +++ b/hugr-core/src/std_extensions/collections.rs @@ -51,7 +51,9 @@ impl ListValue { } /// Create a new [CustomConst] for an empty list of values of type `typ`. + /// Note this will be valid only if `typ` is concrete (does not contain type variables). pub fn new_empty(typ: Type) -> Self { + debug_assert!(!typ.contains_vars()); Self(vec![], typ) } @@ -123,6 +125,8 @@ impl CustomConst for ListValue { #[allow(non_camel_case_types)] #[non_exhaustive] pub enum ListOp { + /// Create a new empty list + new, /// Pop from the end of list. Return an optional value. pop, /// Push to end of list. Return the new list. @@ -160,6 +164,7 @@ impl ListOp { let e = Type::new_var_use(0, TypeBound::Any); let l = self.list_type(list_type_def, 0); match self { + new => self.list_polytype(Vec::::new(), l).into(), pop => self .list_polytype(vec![l.clone()], vec![l, Type::from(option_type(e))]) .into(), @@ -237,6 +242,7 @@ impl MakeOpDef for ListOp { use ListOp::*; match self { + new => "Create a new empty list", pop => "Pop from the back of list. Returns an optional value.", push => "Push to the back of list", get => "Lookup an element in a list by index. Panics if the index is out of bounds.", diff --git a/hugr-core/src/std_extensions/collections/list_fold.rs b/hugr-core/src/std_extensions/collections/list_fold.rs index a7e037f6f..1f88bc7ae 100644 --- a/hugr-core/src/std_extensions/collections/list_fold.rs +++ b/hugr-core/src/std_extensions/collections/list_fold.rs @@ -14,6 +14,7 @@ use super::{ListOp, ListValue}; pub(super) fn set_fold(op: &ListOp, def: &mut OpDef) { match op { + ListOp::new => def.set_constant_folder(NewFold), ListOp::pop => def.set_constant_folder(PopFold), ListOp::push => def.set_constant_folder(PushFold), ListOp::get => def.set_constant_folder(GetFold), @@ -23,6 +24,24 @@ pub(super) fn set_fold(op: &ListOp, def: &mut OpDef) { } } +pub struct NewFold; + +impl ConstFold for NewFold { + fn fold( + &self, + type_args: &[TypeArg], + _consts: &[(crate::IncomingPort, crate::ops::Value)], + ) -> ConstFoldResult { + let [TypeArg::Type { ty }] = type_args else { + panic!("Should have just element type") + }; + if ty.contains_vars() { + None + } else { + Some(vec![(0.into(), ListValue::new_empty(ty.clone()).into())]) + } + } +} pub struct PopFold; impl ConstFold for PopFold {