From f2963a417cfac6bd93c007fe25db03294276d747 Mon Sep 17 00:00:00 2001 From: Craig Roy Date: Tue, 14 Nov 2023 15:29:37 +0000 Subject: [PATCH 01/11] fix: Special case FuncDefn in extension validation --- src/hugr/validate.rs | 14 +++++++++----- src/hugr/validate/test.rs | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/hugr/validate.rs b/src/hugr/validate.rs index 0d0724379..2725c5e25 100644 --- a/src/hugr/validate.rs +++ b/src/hugr/validate.rs @@ -200,11 +200,15 @@ impl<'a, 'b> ValidationContext<'a, 'b> { // Secondly that the node has correct children self.validate_children(node, node_type)?; - // If this is a container with I/O nodes, check that the extension they - // define match the extensions of the container. - if let Some([input, output]) = self.hugr.get_io(node) { - self.extension_validator - .validate_io_extensions(node, input, output)?; + // FuncDefns have no resources since they're static nodes, but the + // functions they define can have any extension delta. + if node_type.tag() != OpTag::FuncDefn { + // If this is a container with I/O nodes, check that the extension they + // define match the extensions of the container. + if let Some([input, output]) = self.hugr.get_io(node) { + self.extension_validator + .validate_io_extensions(node, input, output)?; + } } Ok(()) diff --git a/src/hugr/validate/test.rs b/src/hugr/validate/test.rs index 2cf5d1812..43087d821 100644 --- a/src/hugr/validate/test.rs +++ b/src/hugr/validate/test.rs @@ -563,7 +563,7 @@ fn extensions_mismatch() -> Result<(), BuildError> { assert_matches!( handle, Err(ValidationError::ExtensionError( - ExtensionError::ParentIOExtensionMismatch { .. } + ExtensionError::TgtExceedsSrcExtensionsAtPort { .. } )) ); Ok(()) From 64fbfc39861cca39a75830735257c4db7dee3e2b Mon Sep 17 00:00:00 2001 From: Craig Roy Date: Tue, 14 Nov 2023 15:39:59 +0000 Subject: [PATCH 02/11] fix(Inference): Don't add I/O constraints for `FuncDefn`s --- src/extension/infer.rs | 8 +++- src/extension/infer/test.rs | 79 ++++++++++++++++++++++++++++++++++++- 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/src/extension/infer.rs b/src/extension/infer.rs index d468017a7..831dc6fdd 100644 --- a/src/extension/infer.rs +++ b/src/extension/infer.rs @@ -279,7 +279,13 @@ impl UnificationContext { let m_input_node = self.make_or_get_meta(input, dir); self.add_constraint(m_input_node, Constraint::Equal(m_input)); let m_output_node = self.make_or_get_meta(output, dir); - self.add_constraint(m_output_node, Constraint::Equal(m_output)); + // If the parent node is a FuncDefn, it's input_resources + // should always be empty, meaning if the function adds + // resources, they shouldn't be equal to the parent's output + // (which will also be empty.) + if node_type.tag() != OpTag::FuncDefn { + self.add_constraint(m_output_node, Constraint::Equal(m_output)); + } } } diff --git a/src/extension/infer/test.rs b/src/extension/infer/test.rs index 480a1d5bc..95df9420b 100644 --- a/src/extension/infer/test.rs +++ b/src/extension/infer/test.rs @@ -2,10 +2,15 @@ use std::error::Error; use super::*; use crate::builder::test::closed_dfg_root_hugr; -use crate::builder::{DFGBuilder, Dataflow, DataflowHugr}; +use crate::builder::{ + Container, DFGBuilder, Dataflow, DataflowHugr, DataflowSubContainer, HugrBuilder, ModuleBuilder, +}; use crate::extension::prelude::QB_T; use crate::extension::ExtensionId; -use crate::extension::{prelude::PRELUDE_REGISTRY, ExtensionSet}; +use crate::extension::{ + prelude::{ConstUsize, PRELUDE_REGISTRY, USIZE_T}, + ExtensionSet, +}; use crate::hugr::{validate::ValidationError, Hugr, HugrMut, HugrView, NodeType}; use crate::macros::const_extension_ids; use crate::ops::custom::{ExternalOp, OpaqueOp}; @@ -962,3 +967,73 @@ fn sccs() { Some(&ExtensionSet::from_iter([A, B, C, UNKNOWN_EXTENSION])) ); } + +#[test] +fn simple_funcdefn() -> Result<(), Box> { + let mut builder = ModuleBuilder::new(); + let mut func_builder = builder.define_function( + "F", + FunctionType::new(vec![NAT], vec![NAT]) + .with_extension_delta(&ExtensionSet::singleton(&A)) + .pure(), + )?; + + let [w] = func_builder.input_wires_arr(); + let lift = func_builder.add_dataflow_op( + ops::LeafOp::Lift { + type_row: type_row![NAT], + new_extension: A, + }, + [w], + )?; + let [w] = lift.outputs_arr(); + func_builder.finish_with_outputs([w])?; + builder.finish_hugr(&PRELUDE_REGISTRY)?; + Ok(()) +} + +#[test] +// Define a function "g" inside "f", which defines a function which adds to +// the graph. Tests that the resources of the graph of "g" aren't being +// constrained to match those of the FuncDefn node. +fn funcdefn() -> Result<(), Box> { + use crate::builder::{Container, Dataflow}; + use crate::values::Value; + + let mut builder = ModuleBuilder::new(); + let mut func_builder = builder.define_function( + "F", + FunctionType::new(vec![NAT], vec![NAT]) + .with_extension_delta(&ExtensionSet::singleton(&A)) + .pure(), + )?; + + let mut nested_func_builder = func_builder.define_function( + "G", + FunctionType::new(vec![NAT], vec![NAT]) + .with_extension_delta(&ExtensionSet::singleton(&A)) + .pure(), + )?; + + let [w] = nested_func_builder.input_wires_arr(); + let lift = nested_func_builder.add_dataflow_op( + ops::LeafOp::Lift { + type_row: type_row![NAT], + new_extension: A, + }, + [w], + )?; + let [w] = lift.outputs_arr(); + let g_id = nested_func_builder.finish_with_outputs([w])?; + + let int_value: Value = ConstUsize::new(42).into(); + let k_node = func_builder.add_constant(ops::Const::new(int_value, USIZE_T).unwrap(), None)?; + let k = func_builder.load_const(&k_node)?; + let call = func_builder.call(g_id.handle(), [k])?; + let [w] = call.outputs_arr(); + func_builder.finish_with_outputs([w])?; + + let hugr = builder.finish_hugr(&PRELUDE_REGISTRY)?; + infer_extensions(&hugr)?; + Ok(()) +} From d4165431432807321ef81a3d68e43ea68dbaef89 Mon Sep 17 00:00:00 2001 From: Craig Roy Date: Tue, 14 Nov 2023 16:41:38 +0000 Subject: [PATCH 03/11] test: Add another test of parent-child I/O validation --- src/hugr/validate/test.rs | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/hugr/validate/test.rs b/src/hugr/validate/test.rs index 43087d821..3db608a68 100644 --- a/src/hugr/validate/test.rs +++ b/src/hugr/validate/test.rs @@ -750,3 +750,51 @@ fn invalid_types() { SignatureError::TypeArgMismatch(TypeArgError::WrongNumberArgs(2, 1)) ); } + +#[test] +fn parent_io_mismatch() { + let mut hugr = Hugr::new(NodeType::new_pure(ops::DFG { + signature: FunctionType::new(type_row![USIZE_T], type_row![USIZE_T]), + })); + + let input = hugr + .add_node_with_parent( + hugr.root(), + NodeType::new_pure(ops::Input { + types: type_row![USIZE_T], + }), + ) + .unwrap(); + let output = hugr + .add_node_with_parent( + hugr.root(), + NodeType::new( + ops::Output { + types: type_row![USIZE_T], + }, + ExtensionSet::singleton(&XB), + ), + ) + .unwrap(); + + let lift = hugr + .add_node_with_parent( + hugr.root(), + NodeType::new_pure(ops::LeafOp::Lift { + type_row: type_row![USIZE_T], + new_extension: XB, + }), + ) + .unwrap(); + + hugr.connect(input, 0, lift, 0).unwrap(); + hugr.connect(lift, 0, output, 0).unwrap(); + + let result = hugr.validate(&PRELUDE_REGISTRY); + assert_matches!( + result, + Err(ValidationError::ExtensionError( + ExtensionError::ParentIOExtensionMismatch { .. } + )) + ); +} From 3f87b8ddc6f0439b164cb3dd7087dc5b9d18b7f7 Mon Sep 17 00:00:00 2001 From: Craig Roy Date: Wed, 15 Nov 2023 09:13:31 +0000 Subject: [PATCH 04/11] cosmetic: names --- src/extension/infer.rs | 2 +- src/extension/infer/test.rs | 25 +++++++++++++------------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/extension/infer.rs b/src/extension/infer.rs index 831dc6fdd..58fc51b7e 100644 --- a/src/extension/infer.rs +++ b/src/extension/infer.rs @@ -279,7 +279,7 @@ impl UnificationContext { let m_input_node = self.make_or_get_meta(input, dir); self.add_constraint(m_input_node, Constraint::Equal(m_input)); let m_output_node = self.make_or_get_meta(output, dir); - // If the parent node is a FuncDefn, it's input_resources + // If the parent node is a FuncDefn, it's input_extensions // should always be empty, meaning if the function adds // resources, they shouldn't be equal to the parent's output // (which will also be empty.) diff --git a/src/extension/infer/test.rs b/src/extension/infer/test.rs index 95df9420b..b8fd17571 100644 --- a/src/extension/infer/test.rs +++ b/src/extension/infer/test.rs @@ -996,27 +996,27 @@ fn simple_funcdefn() -> Result<(), Box> { // Define a function "g" inside "f", which defines a function which adds to // the graph. Tests that the resources of the graph of "g" aren't being // constrained to match those of the FuncDefn node. -fn funcdefn() -> Result<(), Box> { +fn nested_funcdefn() -> Result<(), Box> { use crate::builder::{Container, Dataflow}; use crate::values::Value; let mut builder = ModuleBuilder::new(); - let mut func_builder = builder.define_function( - "F", + let mut outer_func_builder = builder.define_function( + "outer", FunctionType::new(vec![NAT], vec![NAT]) .with_extension_delta(&ExtensionSet::singleton(&A)) .pure(), )?; - let mut nested_func_builder = func_builder.define_function( - "G", + let mut inner_func_builder = outer_func_builder.define_function( + "inner", FunctionType::new(vec![NAT], vec![NAT]) .with_extension_delta(&ExtensionSet::singleton(&A)) .pure(), )?; - let [w] = nested_func_builder.input_wires_arr(); - let lift = nested_func_builder.add_dataflow_op( + let [w] = inner_func_builder.input_wires_arr(); + let lift = inner_func_builder.add_dataflow_op( ops::LeafOp::Lift { type_row: type_row![NAT], new_extension: A, @@ -1024,14 +1024,15 @@ fn funcdefn() -> Result<(), Box> { [w], )?; let [w] = lift.outputs_arr(); - let g_id = nested_func_builder.finish_with_outputs([w])?; + let g_id = inner_func_builder.finish_with_outputs([w])?; let int_value: Value = ConstUsize::new(42).into(); - let k_node = func_builder.add_constant(ops::Const::new(int_value, USIZE_T).unwrap(), None)?; - let k = func_builder.load_const(&k_node)?; - let call = func_builder.call(g_id.handle(), [k])?; + let k_node = + outer_func_builder.add_constant(ops::Const::new(int_value, USIZE_T).unwrap(), None)?; + let k = outer_func_builder.load_const(&k_node)?; + let call = outer_func_builder.call(g_id.handle(), [k])?; let [w] = call.outputs_arr(); - func_builder.finish_with_outputs([w])?; + outer_func_builder.finish_with_outputs([w])?; let hugr = builder.finish_hugr(&PRELUDE_REGISTRY)?; infer_extensions(&hugr)?; From 72d8013d45814a8429b86567f667bc5333ecc697 Mon Sep 17 00:00:00 2001 From: Craig Roy Date: Thu, 16 Nov 2023 09:23:32 +0000 Subject: [PATCH 05/11] tests: Add test of FuncDefn signature not matching its graph --- src/extension/infer/test.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/extension/infer/test.rs b/src/extension/infer/test.rs index b8fd17571..37f1cfcec 100644 --- a/src/extension/infer/test.rs +++ b/src/extension/infer/test.rs @@ -1038,3 +1038,33 @@ fn nested_funcdefn() -> Result<(), Box> { infer_extensions(&hugr)?; Ok(()) } + +#[test] +fn funcdefn_signature_mismatch() -> Result<(), Box> { + let mut builder = ModuleBuilder::new(); + let mut func_builder = builder.define_function( + "F", + FunctionType::new(vec![NAT], vec![NAT]) + .with_extension_delta(&ExtensionSet::singleton(&A)) + .pure(), + )?; + + let [w] = func_builder.input_wires_arr(); + let lift = func_builder.add_dataflow_op( + ops::LeafOp::Lift { + type_row: type_row![NAT], + new_extension: B, + }, + [w], + )?; + let [w] = lift.outputs_arr(); + func_builder.finish_with_outputs([w])?; + let result = builder.finish_prelude_hugr(); + assert_matches!( + result, + Err(ValidationError::CantInfer( + InferExtensionError::MismatchedConcreteWithLocations { .. } + )) + ); + Ok(()) +} From bbbdb1795a6695ae6e6753ccfb149d30cf79e8f7 Mon Sep 17 00:00:00 2001 From: Craig Roy Date: Thu, 16 Nov 2023 09:25:21 +0000 Subject: [PATCH 06/11] doc: Update comments --- src/extension/infer.rs | 11 ++++++----- src/extension/infer/test.rs | 6 +++--- src/hugr/validate/test.rs | 2 ++ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/extension/infer.rs b/src/extension/infer.rs index 58fc51b7e..f707e4684 100644 --- a/src/extension/infer.rs +++ b/src/extension/infer.rs @@ -279,11 +279,12 @@ impl UnificationContext { let m_input_node = self.make_or_get_meta(input, dir); self.add_constraint(m_input_node, Constraint::Equal(m_input)); let m_output_node = self.make_or_get_meta(output, dir); - // If the parent node is a FuncDefn, it's input_extensions - // should always be empty, meaning if the function adds - // resources, they shouldn't be equal to the parent's output - // (which will also be empty.) - if node_type.tag() != OpTag::FuncDefn { + // If the parent node is a FuncDefn, it will have no + // op_signature, so the Incoming and Outgoing ports will + // have equal extension requirements. + // The function that it contains, however, may have an + // extension delta, so its output shouldn't be equal to the + // FuncDefn's output. self.add_constraint(m_output_node, Constraint::Equal(m_output)); } } diff --git a/src/extension/infer/test.rs b/src/extension/infer/test.rs index 37f1cfcec..965557c81 100644 --- a/src/extension/infer/test.rs +++ b/src/extension/infer/test.rs @@ -993,9 +993,9 @@ fn simple_funcdefn() -> Result<(), Box> { } #[test] -// Define a function "g" inside "f", which defines a function which adds to -// the graph. Tests that the resources of the graph of "g" aren't being -// constrained to match those of the FuncDefn node. +// Define a function "inner" as a child of "outer", which defines a function +// which adds an extension requirement. Tests that the resources of the graph +// of "outer" aren't being constrained to match those of the FuncDefn node. fn nested_funcdefn() -> Result<(), Box> { use crate::builder::{Container, Dataflow}; use crate::values::Value; diff --git a/src/hugr/validate/test.rs b/src/hugr/validate/test.rs index 3db608a68..2a79a2897 100644 --- a/src/hugr/validate/test.rs +++ b/src/hugr/validate/test.rs @@ -753,6 +753,8 @@ fn invalid_types() { #[test] fn parent_io_mismatch() { + // The DFG node doesn't declare that it has a non-empty extension delta, + // but it's child graph does, causing a mismatch. let mut hugr = Hugr::new(NodeType::new_pure(ops::DFG { signature: FunctionType::new(type_row![USIZE_T], type_row![USIZE_T]), })); From 7671d02005f8fba9ff9c3a0ce75ddf33aa259e6b Mon Sep 17 00:00:00 2001 From: Craig Roy Date: Thu, 16 Nov 2023 10:34:55 +0000 Subject: [PATCH 07/11] Add a test; refactor; reinstate deleted line --- src/extension/infer.rs | 1 + src/extension/infer/test.rs | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/extension/infer.rs b/src/extension/infer.rs index f707e4684..8b60c0ac8 100644 --- a/src/extension/infer.rs +++ b/src/extension/infer.rs @@ -285,6 +285,7 @@ impl UnificationContext { // The function that it contains, however, may have an // extension delta, so its output shouldn't be equal to the // FuncDefn's output. + if node_type.tag() != OpTag::FuncDefn { self.add_constraint(m_output_node, Constraint::Equal(m_output)); } } diff --git a/src/extension/infer/test.rs b/src/extension/infer/test.rs index 965557c81..2cfb044ae 100644 --- a/src/extension/infer/test.rs +++ b/src/extension/infer/test.rs @@ -988,7 +988,7 @@ fn simple_funcdefn() -> Result<(), Box> { )?; let [w] = lift.outputs_arr(); func_builder.finish_with_outputs([w])?; - builder.finish_hugr(&PRELUDE_REGISTRY)?; + builder.finish_prelude_hugr()?; Ok(()) } @@ -1068,3 +1068,24 @@ fn funcdefn_signature_mismatch() -> Result<(), Box> { ); Ok(()) } + +#[test] +// Test that the difference between a FuncDefn's input and output nodes is being +// constrained to be the same as the extension delta in the FuncDefn signature. +// The FuncDefn here is declared to add resource "A", but its body just wires +// the input to the output. +fn funcdefn_signature_mismatch2() -> Result<(), Box> { + let mut builder = ModuleBuilder::new(); + let func_builder = builder.define_function( + "F", + FunctionType::new(vec![NAT], vec![NAT]) + .with_extension_delta(&ExtensionSet::singleton(&A)) + .pure(), + )?; + + let [w] = func_builder.input_wires_arr(); + func_builder.finish_with_outputs([w])?; + let result = builder.finish_prelude_hugr(); + assert_matches!(result, Err(ValidationError::CantInfer(..))); + Ok(()) +} From 97a55a8422a2f0b0c98186b7b918dcc953b4b29e Mon Sep 17 00:00:00 2001 From: Craig Roy Date: Thu, 16 Nov 2023 10:36:44 +0000 Subject: [PATCH 08/11] Update test (but it doesn't pass) --- src/extension/infer/test.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/extension/infer/test.rs b/src/extension/infer/test.rs index 2cfb044ae..27c46e8e9 100644 --- a/src/extension/infer/test.rs +++ b/src/extension/infer/test.rs @@ -1004,10 +1004,11 @@ fn nested_funcdefn() -> Result<(), Box> { let mut outer_func_builder = builder.define_function( "outer", FunctionType::new(vec![NAT], vec![NAT]) - .with_extension_delta(&ExtensionSet::singleton(&A)) + .with_extension_delta(&ExtensionSet::from_iter([A, B])) .pure(), )?; + // The inner function is created with empty input_extensions let mut inner_func_builder = outer_func_builder.define_function( "inner", FunctionType::new(vec![NAT], vec![NAT]) @@ -1024,13 +1025,17 @@ fn nested_funcdefn() -> Result<(), Box> { [w], )?; let [w] = lift.outputs_arr(); - let g_id = inner_func_builder.finish_with_outputs([w])?; + let inner = inner_func_builder.finish_with_outputs([w])?; let int_value: Value = ConstUsize::new(42).into(); - let k_node = - outer_func_builder.add_constant(ops::Const::new(int_value, USIZE_T).unwrap(), None)?; + let k_node = outer_func_builder.add_constant( + ops::Const::new(int_value, USIZE_T).unwrap(), + ExtensionSet::singleton(&B), + )?; let k = outer_func_builder.load_const(&k_node)?; - let call = outer_func_builder.call(g_id.handle(), [k])?; + // The input extensions for this call node will be solved to "B" to match + // the Const and LoadConst nodes. The "inner" graph is pure + let call = outer_func_builder.call(inner.handle(), [k])?; let [w] = call.outputs_arr(); outer_func_builder.finish_with_outputs([w])?; From 0cdd1eee15054cc58ede89b4ee7aee89f6380d68 Mon Sep 17 00:00:00 2001 From: Craig Roy Date: Thu, 16 Nov 2023 10:39:03 +0000 Subject: [PATCH 09/11] tests: Remove nested test - it's for a later PR --- src/extension/infer/test.rs | 57 +------------------------------------ 1 file changed, 1 insertion(+), 56 deletions(-) diff --git a/src/extension/infer/test.rs b/src/extension/infer/test.rs index 27c46e8e9..9fd550b8e 100644 --- a/src/extension/infer/test.rs +++ b/src/extension/infer/test.rs @@ -7,10 +7,7 @@ use crate::builder::{ }; use crate::extension::prelude::QB_T; use crate::extension::ExtensionId; -use crate::extension::{ - prelude::{ConstUsize, PRELUDE_REGISTRY, USIZE_T}, - ExtensionSet, -}; +use crate::extension::{prelude::PRELUDE_REGISTRY, ExtensionSet}; use crate::hugr::{validate::ValidationError, Hugr, HugrMut, HugrView, NodeType}; use crate::macros::const_extension_ids; use crate::ops::custom::{ExternalOp, OpaqueOp}; @@ -992,58 +989,6 @@ fn simple_funcdefn() -> Result<(), Box> { Ok(()) } -#[test] -// Define a function "inner" as a child of "outer", which defines a function -// which adds an extension requirement. Tests that the resources of the graph -// of "outer" aren't being constrained to match those of the FuncDefn node. -fn nested_funcdefn() -> Result<(), Box> { - use crate::builder::{Container, Dataflow}; - use crate::values::Value; - - let mut builder = ModuleBuilder::new(); - let mut outer_func_builder = builder.define_function( - "outer", - FunctionType::new(vec![NAT], vec![NAT]) - .with_extension_delta(&ExtensionSet::from_iter([A, B])) - .pure(), - )?; - - // The inner function is created with empty input_extensions - let mut inner_func_builder = outer_func_builder.define_function( - "inner", - FunctionType::new(vec![NAT], vec![NAT]) - .with_extension_delta(&ExtensionSet::singleton(&A)) - .pure(), - )?; - - let [w] = inner_func_builder.input_wires_arr(); - let lift = inner_func_builder.add_dataflow_op( - ops::LeafOp::Lift { - type_row: type_row![NAT], - new_extension: A, - }, - [w], - )?; - let [w] = lift.outputs_arr(); - let inner = inner_func_builder.finish_with_outputs([w])?; - - let int_value: Value = ConstUsize::new(42).into(); - let k_node = outer_func_builder.add_constant( - ops::Const::new(int_value, USIZE_T).unwrap(), - ExtensionSet::singleton(&B), - )?; - let k = outer_func_builder.load_const(&k_node)?; - // The input extensions for this call node will be solved to "B" to match - // the Const and LoadConst nodes. The "inner" graph is pure - let call = outer_func_builder.call(inner.handle(), [k])?; - let [w] = call.outputs_arr(); - outer_func_builder.finish_with_outputs([w])?; - - let hugr = builder.finish_hugr(&PRELUDE_REGISTRY)?; - infer_extensions(&hugr)?; - Ok(()) -} - #[test] fn funcdefn_signature_mismatch() -> Result<(), Box> { let mut builder = ModuleBuilder::new(); From 417ffc15871c2b378d6bd170297ea88c5d252b17 Mon Sep 17 00:00:00 2001 From: Craig Roy Date: Thu, 16 Nov 2023 10:47:00 +0000 Subject: [PATCH 10/11] doc: Improve wording of comment --- src/hugr/validate/test.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hugr/validate/test.rs b/src/hugr/validate/test.rs index 2a79a2897..0c6594a95 100644 --- a/src/hugr/validate/test.rs +++ b/src/hugr/validate/test.rs @@ -753,8 +753,8 @@ fn invalid_types() { #[test] fn parent_io_mismatch() { - // The DFG node doesn't declare that it has a non-empty extension delta, - // but it's child graph does, causing a mismatch. + // The DFG node declares that it has an empty extension delta, + // but it's child graph adds extension "XB", causing a mismatch. let mut hugr = Hugr::new(NodeType::new_pure(ops::DFG { signature: FunctionType::new(type_row![USIZE_T], type_row![USIZE_T]), })); From 31d2d5499ba6879df065d173ca010b3b41f1c874 Mon Sep 17 00:00:00 2001 From: Craig Roy Date: Thu, 16 Nov 2023 12:11:03 +0000 Subject: [PATCH 11/11] doc: Add comments specifying the limitations of tests --- src/extension/infer.rs | 4 ++++ src/extension/infer/test.rs | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/extension/infer.rs b/src/extension/infer.rs index 7a1b03cfb..cd41a3cfe 100644 --- a/src/extension/infer.rs +++ b/src/extension/infer.rs @@ -285,6 +285,10 @@ impl UnificationContext { // The function that it contains, however, may have an // extension delta, so its output shouldn't be equal to the // FuncDefn's output. + // + // TODO: Add a constraint that the extensions of the output + // node of a FuncDefn should be those of the input node plus + // the extension delta specified in the function signature. if node_type.tag() != OpTag::FuncDefn { self.add_constraint(m_output_node, Constraint::Equal(m_output)); } diff --git a/src/extension/infer/test.rs b/src/extension/infer/test.rs index 8f51e6236..f748c4570 100644 --- a/src/extension/infer/test.rs +++ b/src/extension/infer/test.rs @@ -966,6 +966,11 @@ fn sccs() { } #[test] +/// Note: This test is relying on the builder's `define_function` doing the +/// right thing: it takes input resources via a [`Signature`], which it passes +/// to `create_with_io`, creating concrete resource sets. +/// Inference can still fail for a valid FuncDefn hugr created without using +/// the builder API. fn simple_funcdefn() -> Result<(), Box> { let mut builder = ModuleBuilder::new(); let mut func_builder = builder.define_function(