Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
3ec0890
Remove TypeRow(RV) from Type(RV), add from <const N: usize> [Type(RV)…
acl-cqc Jan 1, 2026
7e65a1b
Merge remote-tracking branch 'origin/main' into acl/no_1type_row
acl-cqc Jan 30, 2026
33618ba
Grab most type_param.rs changes
acl-cqc Feb 16, 2026
d383d39
And copy much of type_row.rs too
acl-cqc Feb 16, 2026
a3a5f2c
Remove TypeEnum, RowVar, MaybeRV, etc.
acl-cqc Feb 16, 2026
92083e2
GeneralSum (w/out bound), serialize.rs
acl-cqc Feb 23, 2026
ae898bd
copy signature.rs/poly_func.rs
acl-cqc Feb 16, 2026
c88231e
A bunch of others...onto another stage of typechecking
acl-cqc Feb 18, 2026
6948450
WIP types.rs/type_param.rs, conversions, etc.
acl-cqc Feb 23, 2026
94625c2
collections (matches vs TypeArg::Runtime), pub(crate) Term::lub/copyable
acl-cqc Feb 24, 2026
b7fc0b8
updates to hugr-passes; non-test code builds
acl-cqc Feb 24, 2026
041d536
many test fixes, except new_tuple
acl-cqc Feb 24, 2026
73c4cec
new_tuple takes term; tests compile; fix prelude
acl-cqc Feb 24, 2026
cc22ad5
clippy+fmt
acl-cqc Feb 24, 2026
573d59d
fix some tests, revert signature of SumType::new_tuple, Display for T…
acl-cqc Feb 25, 2026
9c43e4b
fix serialization of GeneralSum
acl-cqc Feb 25, 2026
57d7edf
Move as_sum/as_extension into Term; fmt; doc new_row_var_use
acl-cqc Feb 25, 2026
86b1e89
hugr-llvm
acl-cqc Feb 25, 2026
e10f2c5
docs
acl-cqc Feb 25, 2026
af2a6f9
clippy+benchmarks
acl-cqc Feb 25, 2026
8805064
update hugr-llvm snapshots
acl-cqc Feb 25, 2026
b996510
update snapshots more
acl-cqc Feb 25, 2026
4f7be66
Remove TypeRV (use Term)
acl-cqc Feb 25, 2026
0ac2b53
Make TypeRowRV a struct (the only panicking new); rm GeneralSum, SerT…
acl-cqc Feb 25, 2026
c563bde
docs
acl-cqc Feb 25, 2026
cfed69d
comment re. Type::validate
acl-cqc Feb 26, 2026
2b231ae
Merge remote-tracking branch 'origin/main' into acl/no_1type_row
acl-cqc Mar 11, 2026
3cbda59
Merge remote-tracking branch 'origin/main' into acl/no_1type_row
acl-cqc Mar 11, 2026
88a0c0d
move validate/substitute into trait Substitutable
acl-cqc Mar 12, 2026
62e67d9
Reparametrize signature
acl-cqc Mar 12, 2026
f42f66e
Add PartialEq<TypeRowRV> for TypeRow
acl-cqc Mar 12, 2026
9035f6b
Reintroduce parametrized PolyFuncTypeBase...problems with deriving AR…
acl-cqc Mar 12, 2026
cfe35bf
Manually impl the ARbitrary's, it's straightforward even if tedious
acl-cqc Mar 12, 2026
21d1db9
Move Substitutable into internals module to fix private_bounds warning
acl-cqc Mar 13, 2026
531719e
doc
acl-cqc Mar 13, 2026
16b4c5e
Merge branch 'acl/no_1type_row' into acl/type_wraps_term
acl-cqc Mar 13, 2026
34cb99d
Fix json-encoding of type variables (showed only in extension defs)
acl-cqc Mar 13, 2026
2962d96
TypeRowRV::new() is const no-args; use try_from, but use safe ctors more
acl-cqc Mar 13, 2026
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
28 changes: 18 additions & 10 deletions hugr-core/src/builder/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,8 +481,8 @@ pub(crate) mod test {
use crate::metadata::Metadata;
use crate::ops::{FuncDecl, FuncDefn, OpParent, OpTag, OpTrait, Value, handle::NodeHandle};
use crate::std_extensions::logic::test::and_op;
use crate::types::type_param::TypeParam;
use crate::types::{EdgeKind, FuncValueType, RowVariable, Signature, Type, TypeBound, TypeRV};
use crate::types::type_param::{TermTypeError, TypeParam};
use crate::types::{EdgeKind, FuncValueType, Signature, Term, Type, TypeBound, TypeRowRV};
use crate::utils::test_quantum_extension::h_gate;
use crate::{Wire, builder::test::n_identity, type_row};

Expand Down Expand Up @@ -926,7 +926,7 @@ pub(crate) mod test {
#[test]
fn no_outer_row_variables() -> Result<(), BuildError> {
let e = crate::hugr::validate::test::extension_with_eval_parallel();
let tv = TypeRV::new_row_var_use(0, TypeBound::Copyable);
let rv = Term::new_row_var_use(0, TypeBound::Copyable);
// Can *declare* a function that takes a function-value of unknown #args
FunctionBuilder::new(
"bad_eval",
Expand All @@ -935,23 +935,31 @@ pub(crate) mod test {
Signature::new(
[Type::new_function(FuncValueType::new(
[usize_t()],
[tv.clone()],
TypeRowRV::try_from(rv.clone()).unwrap(),
))],
[],
),
),
)?;

// But cannot eval it...
let ev = e.instantiate_extension_op(
"eval",
[vec![usize_t().into()].into(), vec![tv.into()].into()],
let ev = e.instantiate_extension_op("eval", [vec![usize_t()].into(), rv.clone()]);
assert_eq!(
ev,
Err(SignatureError::TypeArgMismatch(
TermTypeError::InvalidValue(Box::new(rv.clone()))
))
);

let ev = e.instantiate_extension_op("eval", [vec![usize_t()].into(), [rv.clone()].into()]);
assert_eq!(
ev,
Err(SignatureError::RowVarWhereTypeExpected {
var: RowVariable(0, TypeBound::Copyable)
})
Err(SignatureError::TypeArgMismatch(
TermTypeError::TypeMismatch {
term: Box::new(rv),
type_: Box::new(TypeBound::Linear.into())
}
))
);
Ok(())
}
Expand Down
122 changes: 50 additions & 72 deletions hugr-core/src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
use crate::Visibility;
use crate::extension::ExtensionRegistry;
use crate::hugr::internal::HugrInternals;
use crate::types::type_param::Term;
use crate::{
Direction, Hugr, HugrView, IncomingPort, Node, NodeIndex as _, Port,
extension::{ExtensionId, OpDef, SignatureFunc},
Expand All @@ -14,10 +13,8 @@ use crate::{
arithmetic::{float_types::ConstF64, int_types::ConstInt},
collections::array::ArrayValue,
},
types::{
CustomType, EdgeKind, FuncTypeBase, MaybeRV, PolyFuncTypeBase, RowVariable, SumType,
TypeBase, TypeBound, TypeEnum, type_param::TermVar, type_row::TypeRowBase,
},
types::type_param::{Term, TermVar},
types::{CustomType, EdgeKind, FuncValueType, Signature, SumType, Type, TypeBound, TypeRow},
};

use hugr_model::v0::bumpalo;
Expand Down Expand Up @@ -342,10 +339,12 @@ impl<'a> Context<'a> {
OpType::FuncDefn(func) => self.with_local_scope(node_id, |this| {
let symbol_name = this.export_func_name(node, &mut meta);

let symbol = this.export_poly_func_type(
let sig = func.signature();
let symbol = this.export_symbol_params(
symbol_name,
Some(func.visibility().clone().into()),
func.signature(),
sig.params(),
|this| this.export_signature(sig.body()),
);
regions = this.bump.alloc_slice_copy(&[this.export_dfg(
node,
Expand All @@ -358,11 +357,12 @@ impl<'a> Context<'a> {

OpType::FuncDecl(func) => self.with_local_scope(node_id, |this| {
let symbol_name = this.export_func_name(node, &mut meta);

let symbol = this.export_poly_func_type(
let sig = func.signature();
let symbol = this.export_symbol_params(
symbol_name,
Some(func.visibility().clone().into()),
func.signature(),
sig.params(),
|this| this.export_signature(sig.body()),
);
table::Operation::DeclareFunc(symbol)
}),
Expand Down Expand Up @@ -507,7 +507,7 @@ impl<'a> Context<'a> {
Some(signature) => {
let num_inputs = signature.input_types().len();
let num_outputs = signature.output_types().len();
let signature = self.export_func_type(signature);
let signature = self.export_signature(signature);
(Some(signature), num_inputs, num_outputs)
}
None => (None, 0, 0),
Expand Down Expand Up @@ -559,7 +559,9 @@ impl<'a> Context<'a> {

let symbol = self.with_local_scope(node, |this| {
let name = this.make_qualified_name(opdef.extension_id(), opdef.name());
this.export_poly_func_type(name, None, poly_func_type)
this.export_symbol_params(name, None, poly_func_type.params(), |this| {
this.export_func_type(poly_func_type.body())
})
});

let meta = {
Expand Down Expand Up @@ -816,60 +818,52 @@ impl<'a> Context<'a> {
}

/// Exports a polymorphic function type.
pub fn export_poly_func_type<RV: MaybeRV>(
pub fn export_symbol_params(
&mut self,
name: &'a str,
visibility: Option<model::Visibility>,
t: &PolyFuncTypeBase<RV>,
params: &[Term],
export_body: impl FnOnce(&mut Self) -> table::TermId,
) -> &'a table::Symbol<'a> {
let mut params = BumpVec::with_capacity_in(t.params().len(), self.bump);
let mut param_vec = BumpVec::with_capacity_in(params.len(), self.bump);
let scope = self
.local_scope
.expect("exporting poly func type outside of local scope");
let visibility = self.bump.alloc(visibility);
for (i, param) in t.params().iter().enumerate() {
for (i, param) in params.iter().enumerate() {
let name = self.bump.alloc_str(&i.to_string());
let r#type = self.export_term(param, Some((scope, i as _)));
let param = table::Param { name, r#type };
params.push(param);
param_vec.push(param);
}

let constraints = self.bump.alloc_slice_copy(&self.local_constraints);
let body = self.export_func_type(t.body());
let body = export_body(self);

self.bump.alloc(table::Symbol {
visibility,
name,
params: params.into_bump_slice(),
params: param_vec.into_bump_slice(),
constraints,
signature: body,
})
}

pub fn export_type<RV: MaybeRV>(&mut self, t: &TypeBase<RV>) -> table::TermId {
self.export_type_enum(t.as_type_enum())
}

pub fn export_type_enum<RV: MaybeRV>(&mut self, t: &TypeEnum<RV>) -> table::TermId {
match t {
TypeEnum::Extension(ext) => self.export_custom_type(ext),
TypeEnum::Alias(alias) => {
let symbol = self.resolve_symbol(self.bump.alloc_str(alias.name()));
self.make_term(table::Term::Apply(symbol, &[]))
}
TypeEnum::Function(func) => self.export_func_type(func),
TypeEnum::Variable(index, _) => {
let node = self.local_scope.expect("local variable out of scope");
self.make_term(table::Term::Var(table::VarId(node, *index as _)))
}
TypeEnum::RowVar(rv) => self.export_row_var(rv.as_rv()),
TypeEnum::Sum(sum) => self.export_sum_type(sum),
}
pub fn export_type(&mut self, t: &Type) -> table::TermId {
self.export_term(t, None)
}

pub fn export_func_type<RV: MaybeRV>(&mut self, t: &FuncTypeBase<RV>) -> table::TermId {
pub fn export_signature(&mut self, t: &Signature) -> table::TermId {
let inputs = self.export_type_row(t.input());
let outputs = self.export_type_row(t.output());
// Ok to use CORE_FN here: the elements of the row will be exported inside a List
self.make_term_apply(model::CORE_FN, &[inputs, outputs])
}

pub fn export_func_type(&mut self, t: &FuncValueType) -> table::TermId {
let inputs = self.export_term(t.input(), None);
let outputs = self.export_term(t.output(), None);
// Ok to use CORE_FN here: the input/output should each be a core List or ListConcat
self.make_term_apply(model::CORE_FN, &[inputs, outputs])
}

Expand All @@ -888,28 +882,12 @@ impl<'a> Context<'a> {
self.make_term(table::Term::Var(table::VarId(node, var.index() as _)))
}

pub fn export_row_var(&mut self, t: &RowVariable) -> table::TermId {
let node = self.local_scope.expect("local variable out of scope");
self.make_term(table::Term::Var(table::VarId(node, t.0 as _)))
}

pub fn export_sum_variants(&mut self, t: &SumType) -> table::TermId {
match t {
SumType::Unit { size } => {
let parts = self.bump.alloc_slice_fill_iter(
(0..*size)
.map(|_| table::SeqPart::Item(self.make_term(table::Term::List(&[])))),
);
self.make_term(table::Term::List(parts))
}
SumType::General { rows } => {
let parts = self.bump.alloc_slice_fill_iter(
rows.iter()
.map(|row| table::SeqPart::Item(self.export_type_row(row))),
);
self.make_term(table::Term::List(parts))
}
}
// Sadly we cannot use alloc_slice_fill_iter because SumType::variants is not an ExactSizeIterator.
let parts = self.bump.alloc_slice_fill_with(t.num_variants(), |i| {
table::SeqPart::Item(self.export_term(t.get_variant(i).unwrap(), None))
});
self.make_term(table::Term::List(parts))
}

pub fn export_sum_type(&mut self, t: &SumType) -> table::TermId {
Expand All @@ -918,27 +896,20 @@ impl<'a> Context<'a> {
}

#[inline]
pub fn export_type_row<RV: MaybeRV>(&mut self, row: &TypeRowBase<RV>) -> table::TermId {
pub fn export_type_row(&mut self, row: &TypeRow) -> table::TermId {
self.export_type_row_with_tail(row, None)
}

pub fn export_type_row_with_tail<RV: MaybeRV>(
pub fn export_type_row_with_tail(
&mut self,
row: &TypeRowBase<RV>,
row: &TypeRow,
tail: Option<table::TermId>,
) -> table::TermId {
let mut parts =
BumpVec::with_capacity_in(row.len() + usize::from(tail.is_some()), self.bump);

for t in row.iter() {
match t.as_type_enum() {
TypeEnum::RowVar(var) => {
parts.push(table::SeqPart::Splice(self.export_row_var(var.as_rv())));
}
_ => {
parts.push(table::SeqPart::Item(self.export_type(t)));
}
}
parts.push(table::SeqPart::Item(self.export_type(t)));
}

if let Some(tail) = tail {
Expand Down Expand Up @@ -982,7 +953,14 @@ impl<'a> Context<'a> {
let item_types = self.export_term(item_types, None);
self.make_term_apply(model::CORE_TUPLE_TYPE, &[item_types])
}
Term::Runtime(ty) => self.export_type(ty),
Term::RuntimeExtension(ext) => self.export_custom_type(ext),
/*TypeEnum::Alias(alias) => {
let symbol = self.resolve_symbol(self.bump.alloc_str(alias.name()));
self.make_term(table::Term::Apply(symbol, &[]))
}*/
Term::RuntimeFunction(func) => self.export_func_type(func),
Term::RuntimeSum(sum) => self.export_sum_type(sum),

Term::BoundedNat(value) => self.make_term(model::Literal::Nat(*value).into()),
Term::String(value) => self.make_term(model::Literal::Str(value.into()).into()),
Term::Float(value) => self.make_term(model::Literal::Float(*value).into()),
Expand Down
8 changes: 4 additions & 4 deletions hugr-core/src/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ use thiserror::Error;
use crate::hugr::IdentList;
use crate::ops::custom::{ExtensionOp, OpaqueOp};
use crate::ops::{OpName, OpNameRef};
use crate::types::RowVariable;
use crate::types::type_param::{TermTypeError, TypeArg, TypeParam};
use crate::types::{CustomType, TypeBound, TypeName};
use crate::types::{Signature, TypeNameRef};
Expand Down Expand Up @@ -518,9 +517,10 @@ pub enum SignatureError {
/// A type variable that was used has not been declared
#[error("Type variable {idx} was not declared ({num_decls} in scope)")]
FreeTypeVar { idx: usize, num_decls: usize },
/// A row variable was found outside of a variable-length row
#[error("Expected a single type, but found row variable {var}")]
RowVarWhereTypeExpected { var: RowVariable },
// ALAN this is now just another TypeArgMismatch
// A row variable was found outside of a variable-length row
//#[error("Expected a single type, but found row variable {var}")]
//RowVarWhereTypeExpected { var: RowVariable },
/// The result of the type application stored in a [Call]
/// is not what we get by applying the type-args to the polymorphic function
///
Expand Down
6 changes: 3 additions & 3 deletions hugr-core/src/extension/op_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::envelope::serde_with::AsBinaryEnvelope;
use crate::ops::{OpName, OpNameRef};
use crate::package::Package;
use crate::types::type_param::{TypeArg, TypeParam, check_term_types};
use crate::types::{FuncValueType, PolyFuncType, PolyFuncTypeRV, Signature};
use crate::types::{FuncValueType, PolyFuncType, PolyFuncTypeRV, Signature, Substitutable};
mod serialize_signature_func;

/// Trait necessary for binary computations of `OpDef` signature
Expand Down Expand Up @@ -614,7 +614,7 @@ pub(super) mod test {
use crate::package::Package;
use crate::std_extensions::collections::list;
use crate::types::type_param::{TermTypeError, TypeParam};
use crate::types::{PolyFuncTypeRV, Signature, Type, TypeArg, TypeBound, TypeRV};
use crate::types::{PolyFuncTypeRV, Signature, Term, Type, TypeArg, TypeBound};
use crate::{Extension, const_extension_ids};

const_extension_ids! {
Expand Down Expand Up @@ -862,7 +862,7 @@ pub(super) mod test {
def.validate_args(&args, &decls).unwrap();
assert_eq!(def.compute_signature(&args), Ok(Signature::new_endo([tv])));
// But not with an external row variable
let arg: TypeArg = TypeRV::new_row_var_use(0, TypeBound::Copyable).into();
let arg: TypeArg = Term::new_row_var_use(0, TypeBound::Copyable);
assert_eq!(
def.compute_signature(std::slice::from_ref(&arg)),
Err(SignatureError::TypeArgMismatch(
Expand Down
Loading
Loading