From 50d5f565d25939d840c2d13b05104d529e1dc7b2 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Tue, 7 May 2024 10:21:12 +0100 Subject: [PATCH 1/4] validate/test.rs: const_extension_ids EXT_ID --- hugr/src/hugr/validate/test.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/hugr/src/hugr/validate/test.rs b/hugr/src/hugr/validate/test.rs index 98fe890ed..94b0f0b3c 100644 --- a/hugr/src/hugr/validate/test.rs +++ b/hugr/src/hugr/validate/test.rs @@ -7,7 +7,7 @@ use crate::builder::{ HugrBuilder, ModuleBuilder, }; use crate::extension::prelude::{BOOL_T, PRELUDE, USIZE_T}; -use crate::extension::{Extension, ExtensionId, TypeDefBound, EMPTY_REG, PRELUDE_REGISTRY}; +use crate::extension::{Extension, TypeDefBound, EMPTY_REG, PRELUDE_REGISTRY}; use crate::hugr::hugrmut::sealed::HugrMutInternals; use crate::hugr::HugrMut; use crate::ops::dataflow::IOTrait; @@ -16,7 +16,7 @@ use crate::std_extensions::logic::test::{and_op, or_op}; use crate::std_extensions::logic::{self, NotOp}; use crate::types::type_param::{TypeArg, TypeArgError}; use crate::types::{CustomType, FunctionType, PolyFuncType, Type, TypeBound, TypeRow}; -use crate::{type_row, IncomingPort}; +use crate::{const_extension_ids, type_row, Direction, IncomingPort, Node}; const NAT: Type = crate::extension::prelude::USIZE_T; @@ -336,10 +336,12 @@ fn unregistered_extension() { h.update_validate(&PRELUDE_REGISTRY).unwrap(); } +const_extension_ids! { + const EXT_ID: ExtensionId = "MyExt"; +} #[test] fn invalid_types() { - let name: ExtensionId = "MyExt".try_into().unwrap(); - let mut e = Extension::new(name.clone()); + let mut e = Extension::new(EXT_ID); e.add_type( "MyContainer".into(), vec![TypeBound::Copyable.into()], @@ -360,7 +362,7 @@ fn invalid_types() { let valid = Type::new_extension(CustomType::new( "MyContainer", vec![TypeArg::Type { ty: USIZE_T }], - name.clone(), + EXT_ID, TypeBound::Any, )); assert_eq!( @@ -374,7 +376,7 @@ fn invalid_types() { let element_outside_bound = CustomType::new( "MyContainer", vec![TypeArg::Type { ty: valid.clone() }], - name.clone(), + EXT_ID, TypeBound::Any, ); assert_eq!( @@ -388,7 +390,7 @@ fn invalid_types() { let bad_bound = CustomType::new( "MyContainer", vec![TypeArg::Type { ty: USIZE_T }], - name.clone(), + EXT_ID, TypeBound::Copyable, ); assert_eq!( @@ -405,7 +407,7 @@ fn invalid_types() { vec![TypeArg::Type { ty: Type::new_extension(bad_bound), }], - name.clone(), + EXT_ID, TypeBound::Any, ); assert_eq!( @@ -419,7 +421,7 @@ fn invalid_types() { let too_many_type_args = CustomType::new( "MyContainer", vec![TypeArg::Type { ty: USIZE_T }, TypeArg::BoundedNat { n: 3 }], - name.clone(), + EXT_ID, TypeBound::Any, ); assert_eq!( From c171e2362fbcebcd87d3ed384b551330c35968c1 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Tue, 7 May 2024 10:23:14 +0100 Subject: [PATCH 2/4] Big test of calling polymorphic function using polymorphic op --- hugr/src/hugr/validate/test.rs | 110 ++++++++++++++++++++++++++++----- 1 file changed, 96 insertions(+), 14 deletions(-) diff --git a/hugr/src/hugr/validate/test.rs b/hugr/src/hugr/validate/test.rs index 94b0f0b3c..6843b11ed 100644 --- a/hugr/src/hugr/validate/test.rs +++ b/hugr/src/hugr/validate/test.rs @@ -3,15 +3,17 @@ use cool_asserts::assert_matches; use super::*; use crate::builder::test::closed_dfg_root_hugr; use crate::builder::{ - BuildError, Container, Dataflow, DataflowHugr, DataflowSubContainer, FunctionBuilder, - HugrBuilder, ModuleBuilder, + BuildError, Container, DFGBuilder, Dataflow, DataflowHugr, DataflowSubContainer, + FunctionBuilder, HugrBuilder, ModuleBuilder, SubContainer, }; -use crate::extension::prelude::{BOOL_T, PRELUDE, USIZE_T}; -use crate::extension::{Extension, TypeDefBound, EMPTY_REG, PRELUDE_REGISTRY}; +use crate::extension::prelude::{BOOL_T, PRELUDE, PRELUDE_ID, USIZE_T}; +use crate::extension::{Extension, ExtensionSet, TypeDefBound, EMPTY_REG, PRELUDE_REGISTRY}; use crate::hugr::hugrmut::sealed::HugrMutInternals; use crate::hugr::HugrMut; use crate::ops::dataflow::IOTrait; -use crate::ops::{self, Noop, Value}; +use crate::ops::handle::NodeHandle; +use crate::ops::leaf::MakeTuple; +use crate::ops::{self, Noop, OpType, Value}; use crate::std_extensions::logic::test::{and_op, or_op}; use crate::std_extensions::logic::{self, NotOp}; use crate::types::type_param::{TypeArg, TypeArgError}; @@ -546,18 +548,98 @@ fn no_polymorphic_consts() -> Result<(), Box> { #[test] fn test_polymorphic_call() -> Result<(), Box> { - let mut m = ModuleBuilder::new(); - let id = m.declare( - "id", + let mut e = Extension::new(EXT_ID); + + let params: Vec = vec![ + TypeBound::Any.into(), + TypeParam::Extensions, + TypeBound::Any.into(), + ]; + let evaled_fn = Type::new_function( + FunctionType::new( + Type::new_var_use(0, TypeBound::Any), + Type::new_var_use(2, TypeBound::Any), + ) + .with_extension_delta(ExtensionSet::type_var(1)), + ); + + e.add_op( + "eval".into(), + "".into(), PolyFuncType::new( - vec![TypeBound::Any.into()], - FunctionType::new_endo(vec![Type::new_var_use(0, TypeBound::Any)]), + params.clone(), + FunctionType::new( + vec![evaled_fn, Type::new_var_use(0, TypeBound::Any)], + Type::new_var_use(2, TypeBound::Any), + ) + .with_extension_delta(ExtensionSet::type_var(1)), ), )?; - let mut f = m.define_function("main", FunctionType::new_endo(vec![USIZE_T]).into())?; - let c = f.call(&id, &[USIZE_T.into()], f.input_wires(), &PRELUDE_REGISTRY)?; - f.finish_with_outputs(c.outputs())?; - let _ = m.finish_prelude_hugr()?; + + fn utou(e: impl Into) -> Type { + Type::new_function(FunctionType::new_endo(USIZE_T).with_extension_delta(e.into())) + } + + let int_pair = Type::new_tuple(type_row![USIZE_T; 2]); + let mut d = DFGBuilder::new( + FunctionType::new( + vec![utou(PRELUDE_ID), int_pair.clone()], + vec![int_pair.clone()], + ) + .with_extension_delta(PRELUDE_ID), + )?; + let f = { + let es = ExtensionSet::type_var(0); + let mut f = d.define_function( + "two_ints", + PolyFuncType::new( + vec![TypeParam::Extensions], + FunctionType::new(vec![utou(es.clone()), int_pair.clone()], int_pair.clone()) + .with_extension_delta(es.clone()), + ), + )?; + let [func, tup] = f.input_wires_arr(); + let mut c = f.conditional_builder( + (vec![type_row![USIZE_T; 2]], tup), + vec![], + type_row![USIZE_T;2], + es.clone(), + )?; + let mut cc = c.case_builder(0)?; + let [i1, i2] = cc.input_wires_arr(); + let op = e.instantiate_extension_op( + "eval", + vec![USIZE_T.into(), TypeArg::Extensions { es }, USIZE_T.into()], + &PRELUDE_REGISTRY, + )?; + let [f1] = cc.add_dataflow_op(op.clone(), [func, i1])?.outputs_arr(); + let [f2] = cc.add_dataflow_op(op, [func, i2])?.outputs_arr(); + cc.finish_with_outputs([f1, f2])?; + let res = c.finish_sub_container()?.outputs(); + let tup = f.add_dataflow_op( + MakeTuple { + tys: type_row![USIZE_T; 2], + }, + res, + )?; + f.finish_with_outputs(tup.outputs())? + }; + + let reg = ExtensionRegistry::try_new([e, PRELUDE.to_owned()])?; + let [func, tup] = d.input_wires_arr(); + let r = d.call( + &f.handle(), + &[TypeArg::Extensions { + es: ExtensionSet::singleton(&PRELUDE_ID), + }], + [func, tup], + ®, + )?; + let h = d.finish_hugr_with_outputs(r.outputs(), ®)?; + let call_ty = h.get_optype(r.node()).dataflow_signature().unwrap(); + let exp_fun_ty = FunctionType::new(vec![utou(PRELUDE_ID), int_pair.clone()], int_pair) + .with_extension_delta(PRELUDE_ID); + assert_eq!(call_ty, exp_fun_ty); Ok(()) } From b6ccdd2fdf7aebcc5ae45088acbbcec6edfefd21 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Tue, 7 May 2024 10:16:47 +0100 Subject: [PATCH 3/4] Comments, rename --- hugr/src/hugr/validate/test.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hugr/src/hugr/validate/test.rs b/hugr/src/hugr/validate/test.rs index 6843b11ed..a02690298 100644 --- a/hugr/src/hugr/validate/test.rs +++ b/hugr/src/hugr/validate/test.rs @@ -562,7 +562,8 @@ fn test_polymorphic_call() -> Result<(), Box> { ) .with_extension_delta(ExtensionSet::type_var(1)), ); - + // The higher-order "eval" operation - takes a function and its argument. + // Note the extension-delta of the eval node includes that of the input function. e.add_op( "eval".into(), "".into(), @@ -581,6 +582,7 @@ fn test_polymorphic_call() -> Result<(), Box> { } let int_pair = Type::new_tuple(type_row![USIZE_T; 2]); + // Root DFG: applies a function int--PRELUDE-->int to each element of a pair of two ints let mut d = DFGBuilder::new( FunctionType::new( vec![utou(PRELUDE_ID), int_pair.clone()], @@ -588,6 +590,7 @@ fn test_polymorphic_call() -> Result<(), Box> { ) .with_extension_delta(PRELUDE_ID), )?; + // ....by calling a function parametrized (int--e-->int, int_pair) -> int_pair let f = { let es = ExtensionSet::type_var(0); let mut f = d.define_function( @@ -627,7 +630,7 @@ fn test_polymorphic_call() -> Result<(), Box> { let reg = ExtensionRegistry::try_new([e, PRELUDE.to_owned()])?; let [func, tup] = d.input_wires_arr(); - let r = d.call( + let call = d.call( &f.handle(), &[TypeArg::Extensions { es: ExtensionSet::singleton(&PRELUDE_ID), @@ -635,8 +638,8 @@ fn test_polymorphic_call() -> Result<(), Box> { [func, tup], ®, )?; - let h = d.finish_hugr_with_outputs(r.outputs(), ®)?; - let call_ty = h.get_optype(r.node()).dataflow_signature().unwrap(); + let h = d.finish_hugr_with_outputs(call.outputs(), ®)?; + let call_ty = h.get_optype(call.node()).dataflow_signature().unwrap(); let exp_fun_ty = FunctionType::new(vec![utou(PRELUDE_ID), int_pair.clone()], int_pair) .with_extension_delta(PRELUDE_ID); assert_eq!(call_ty, exp_fun_ty); From 078dad99393dd60b0c26d869b3288a52a7baafe0 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Tue, 7 May 2024 19:58:09 +0100 Subject: [PATCH 4/4] clippy --- hugr/src/hugr/validate/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hugr/src/hugr/validate/test.rs b/hugr/src/hugr/validate/test.rs index a02690298..6e987a19b 100644 --- a/hugr/src/hugr/validate/test.rs +++ b/hugr/src/hugr/validate/test.rs @@ -631,7 +631,7 @@ fn test_polymorphic_call() -> Result<(), Box> { let reg = ExtensionRegistry::try_new([e, PRELUDE.to_owned()])?; let [func, tup] = d.input_wires_arr(); let call = d.call( - &f.handle(), + f.handle(), &[TypeArg::Extensions { es: ExtensionSet::singleton(&PRELUDE_ID), }],