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!: Allow "Row Variables" declared as List<Type> #804

Merged
merged 70 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
7b242ac
Refactor: break out fn valid_row for validating a TypeRow
acl-cqc Jan 10, 2024
ba05010
Type::{validate,substitute}_in_row, {Substitution,SubstValues}::apply…
acl-cqc Jan 10, 2024
59c5854
[test] types.rs::construct - also validate
acl-cqc Jan 12, 2024
72b4fb2
[tests] poly_func.rs: test row variables
acl-cqc Jan 12, 2024
2cf1e7f
[test] validate Hugr passing around Function of unknown arity
acl-cqc Jan 12, 2024
8899806
[tests]Validation prevents row variables being used in node signatures
acl-cqc Jan 12, 2024
e1f1825
Simplify default apply_typevar_in_row
acl-cqc Jan 12, 2024
1074093
Separate TypeEnum::RowVariable
acl-cqc Jan 12, 2024
4291848
Merge remote-tracking branch 'origin/main' into feat/row_typevar
acl-cqc Apr 15, 2024
98c75a2
Doc updates - no DeBruijn, ref OpDef vs FuncDefn
acl-cqc Apr 15, 2024
b918bee
Remove unused test setup changes
acl-cqc Apr 15, 2024
a096f1a
Merge remote-tracking branch 'origin/main' into feat/row_typevar
acl-cqc May 9, 2024
4b0e23f
Combine Type::substitute(_in_row), doc, add TODOs
acl-cqc May 9, 2024
a0aba20
FunctionType/PolyFuncType validate_varargs (fixed-len not reqd)
acl-cqc May 9, 2024
bd0689f
Type::validate(=>_1type), fix TypeParam to call validate_in_row
acl-cqc May 10, 2024
72f4b98
{subst,valid}_row => TypeRow::{substitute,validate_var_len}
acl-cqc May 10, 2024
d9653aa
Normalize representation of row variable as TypeArg; extend check_typ…
acl-cqc May 10, 2024
15bf177
Test bad schema, test can't fit row variable into type hole
acl-cqc May 10, 2024
bc11c68
Extend validation tests using eval+parallel
acl-cqc May 10, 2024
f39373b
And extend no_outer_row_variables to include unconnected out'port's o…
acl-cqc May 10, 2024
bd39303
comments re. canonicalization, tests
acl-cqc May 10, 2024
ed64d12
clippy
acl-cqc May 11, 2024
d02c9c0
single_type_seq -> seq1ty
acl-cqc May 11, 2024
50b9c85
Merge remote-tracking branch 'origin/main' into feat/row_typevar
acl-cqc May 11, 2024
742ab55
Combine helpers giving extension_with_eval_parallel
acl-cqc May 12, 2024
ce72762
Add RowVar to serialization/tys.py
acl-cqc May 12, 2024
c556a8a
Regenerate schema
acl-cqc May 12, 2024
7214cbc
Really regenerate schema (after poetry install)
acl-cqc May 12, 2024
ce28154
Use Vec<TypeArg> .into() -> TypeArg
acl-cqc May 14, 2024
0e4b232
Add TypeParam::new_list
acl-cqc May 14, 2024
5b39b9c
rowparam() -> rowp.clone()
acl-cqc May 14, 2024
9ae2255
new_row_var => new_row_var_use, some cleanups using .into()
acl-cqc May 14, 2024
412ec08
squash! Add TypeParam::new_list
acl-cqc May 14, 2024
34ed4c9
Fix apply_row_var...TODO cover this
acl-cqc May 14, 2024
85d1969
check_type_arg_rv: improve comment
acl-cqc May 14, 2024
3cf333d
Remove rowvar_in_list using TypeParam::contains
acl-cqc May 14, 2024
2929135
Add Type::row_var_bound
acl-cqc May 14, 2024
0afdaf9
Remove check_type_arg_rv
acl-cqc May 14, 2024
5a8bf88
Use Type .into() -> TypeArg more
acl-cqc May 14, 2024
2e53529
Extend comment that TypeArg::Variable's are not row-vars
acl-cqc May 14, 2024
ed09ae6
type_row.rs: comment ...Variable]*s*
acl-cqc May 14, 2024
8c93c9d
Add check_type_arg tests as rstest cases
acl-cqc May 14, 2024
8811e1a
More tests! (giving up on rstest)
acl-cqc May 14, 2024
d728714
Add a couple of PolyFuncType-serialization tests
acl-cqc May 14, 2024
9af9d01
In validation, panic upon malformed TypeArgVariable
acl-cqc May 15, 2024
ef86cd7
Correct comment in TypeArg::new_var_use
acl-cqc May 15, 2024
0ff4a05
Add anti-row-var checks in TypeRow::get/get_mut
acl-cqc May 15, 2024
b9fc1cf
Make TypeRow::get(_mut) pub only to crate::types
acl-cqc May 15, 2024
bcffd57
Revert "Make TypeRow::get(_mut) pub only to crate::types"
acl-cqc May 15, 2024
98cf6af
row_var_bound -> is_row_var
acl-cqc May 15, 2024
4a41f96
Clarify bound in Type::new_(,row_)var_use
acl-cqc May 15, 2024
5359441
Thank you Doug!
acl-cqc May 15, 2024
fdb19ae
Comments (Function values, "must match" => "must be exactly")
acl-cqc May 15, 2024
d949cc9
Another TypeParam::new_list
acl-cqc May 15, 2024
571d025
Test: p -> seq_param
acl-cqc May 15, 2024
a353026
Test: rowvar = Type::new_row_var_use
acl-cqc May 15, 2024
93536b3
Capture TypeArg::Type substituting-to-multiple in a unit test, fix
acl-cqc May 15, 2024
d339e2c
Another test with a list-of-list-of-type
acl-cqc May 20, 2024
71b3ae2
Use vec![].into() somewhat selectively
acl-cqc May 20, 2024
b77e3c8
Merge 'origin/main' into feat/row_typevar. Proptest failing...
acl-cqc May 20, 2024
91317ae
Fix proptest by local reject
acl-cqc May 20, 2024
3cbccc7
Temp remove TypeRow checks
acl-cqc May 20, 2024
a43e0a1
Merge remote-tracking branch 'origin/main' into feat/row_typevar
acl-cqc May 20, 2024
e0c7162
Add non-debug asserts in FunctionType
acl-cqc May 20, 2024
7ebb596
Combine Type::validate_1type / validate_in_row to validate(bool,...)
acl-cqc May 20, 2024
bc2d358
validate_varargs => validate_var_len
acl-cqc May 20, 2024
5b63d0c
RowVarOutsideRow => RowVarWhereTypeExpected
acl-cqc May 21, 2024
2a28052
check_no_rowvars - ignore index, check whole row - breaks no_outer_ro…
acl-cqc May 21, 2024
c559abc
FunctionType::find_row_var, check in builder and validation (before p…
acl-cqc May 21, 2024
98c1fc9
Tests (rewrite w/out builder; add builder test, using now-pub-crate e…
acl-cqc May 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion hugr/src/builder/build_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::{
types::EdgeKind,
};

use crate::extension::{ExtensionRegistry, ExtensionSet, PRELUDE_REGISTRY};
use crate::extension::{ExtensionRegistry, ExtensionSet, SignatureError, PRELUDE_REGISTRY};
use crate::types::{FunctionType, PolyFuncType, Type, TypeArg, TypeRow};

use itertools::Itertools;
Expand Down Expand Up @@ -645,6 +645,15 @@ fn add_node_with_wires<T: Dataflow + ?Sized>(
inputs: impl IntoIterator<Item = Wire>,
) -> Result<(Node, usize), BuildError> {
let nodetype: NodeType = nodetype.into();
// Check there are no row variables, as that would prevent us
// from indexing into the node's ports in order to wire up
nodetype
.op_signature()
.as_ref()
.and_then(FunctionType::find_rowvar)
.map_or(Ok(()), |(idx, _)| {
Err(SignatureError::RowVarWhereTypeExpected { idx })
})?;
let num_outputs = nodetype.op().value_output_count();
let op_node = data_builder.add_child_node(nodetype.clone());

Expand Down
17 changes: 15 additions & 2 deletions hugr/src/hugr/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::ops::custom::{resolve_opaque_op, CustomOp};
use crate::ops::validate::{ChildrenEdgeData, ChildrenValidationError, EdgeValidationError};
use crate::ops::{FuncDefn, OpTag, OpTrait, OpType, ValidateOp};
use crate::types::type_param::TypeParam;
use crate::types::EdgeKind;
use crate::types::{EdgeKind, FunctionType};
use crate::{Direction, Hugr, Node, Port};

use super::views::{HierarchyView, HugrView, SiblingGraph};
Expand Down Expand Up @@ -211,7 +211,20 @@ impl<'a, 'b> ValidationContext<'a, 'b> {
}
}

// Secondly that the node has correct children
// Secondly, check that the node signature does not contain any row variables.
// (We do this here so it's before we try indexing into the ports of any nodes).
op_type
.dataflow_signature()
.as_ref()
.and_then(FunctionType::find_rowvar)
.map_or(Ok(()), |(idx, _)| {
Err(ValidationError::SignatureError {
node,
cause: SignatureError::RowVarWhereTypeExpected { idx },
})
})?;

// Thirdly that the node has correct children
self.validate_children(node, node_type)?;

Ok(())
Expand Down
29 changes: 16 additions & 13 deletions hugr/src/types/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use itertools::Either;
use std::fmt::{self, Display, Write};

use super::type_param::TypeParam;
use super::{Substitution, Type, TypeRow};
use super::{Substitution, Type, TypeBound, TypeEnum, TypeRow};

use crate::core::PortIndex;
use crate::extension::{ExtensionRegistry, ExtensionSet, SignatureError};
Expand Down Expand Up @@ -98,31 +98,31 @@ impl FunctionType {
/// of bounds.
#[inline]
pub fn in_port_type(&self, port: impl Into<IncomingPort>) -> Option<&Type> {
check_no_rowvars(&self.input);
debug_assert!(self.find_rowvar().is_none());
self.input.get(port.into().index())
}

/// Returns the type of a value output [`Port`]. Returns `None` if the port is out
/// of bounds.
#[inline]
pub fn out_port_type(&self, port: impl Into<OutgoingPort>) -> Option<&Type> {
check_no_rowvars(&self.output);
debug_assert!(self.find_rowvar().is_none());
self.output.get(port.into().index())
}

/// Returns a mutable reference to the type of a value input [`Port`]. Returns `None` if the port is out
/// of bounds.
#[inline]
pub fn in_port_type_mut(&mut self, port: impl Into<IncomingPort>) -> Option<&mut Type> {
check_no_rowvars(&self.input);
debug_assert!(self.find_rowvar().is_none());
self.input.get_mut(port.into().index())
}

/// Returns the type of a value output [`Port`]. Returns `None` if the port is out
/// of bounds.
#[inline]
pub fn out_port_type_mut(&mut self, port: impl Into<OutgoingPort>) -> Option<&mut Type> {
check_no_rowvars(&self.output);
debug_assert!(self.find_rowvar().is_none());
self.output.get_mut(port.into().index())
}

Expand Down Expand Up @@ -193,6 +193,17 @@ impl FunctionType {
}

impl FunctionType {
/// If this FunctionType contains any row variables, return one.
pub fn find_rowvar(&self) -> Option<(usize, 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 sure this should be pub?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was going to have has_rowvars(&self) -> bool and thought that definitely should be pub. Then I realized that when it returned true I'd have to scan through to find one to raise the error I wanted, so why not do that in the same go. I think having some kind of are-there-any-rowvars is a good method to have, I agree this is a slightly non-obvious form for it but it's no worse than the bool one no?

Could return a list of vars, or Vec<(Direction, usize, (usize, TypeBound)> (i.e. where each one was found) or something like that I guess?

Copy link
Collaborator

Choose a reason for hiding this comment

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

It's not the return type it's that I don't think this will have any users, so preferring not to pollute the namespace + docs. If you disagree, no problem.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we should have a query method, yes. When we split FunTypeVarArgs and SignatureType it belongs only on the former (as necessarily false/None for Signature).

self.input
.iter()
.chain(self.output.iter())
.find_map(|t| match t.0 {
TypeEnum::RowVariable(idx, bound) => Some((idx, bound)),
_ => None,
})
}

/// Returns the `Port`s in the signature for a given direction.
#[inline]
pub fn ports(&self, dir: Direction) -> impl Iterator<Item = Port> {
Expand All @@ -214,14 +225,6 @@ impl FunctionType {
}
}

fn check_no_rowvars(row: &TypeRow) {
// debug_assert as feared too expensive to do at every runtime.
// TODO: consider caching the result (invalidate the cache on every get_mut),
// or statically rule out the various "port" methods for FunctionTypes
// that are not node signatures.
debug_assert!(!row.iter().any(Type::is_row_var));
}

impl Display for FunctionType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if !self.input.is_empty() {
Expand Down