Skip to content

refactor(hugrv2)!: combine TypeEnum with Term, no RV parametrization#2895

Draft
acl-cqc wants to merge 38 commits intomainfrom
acl/type_wraps_term
Draft

refactor(hugrv2)!: combine TypeEnum with Term, no RV parametrization#2895
acl-cqc wants to merge 38 commits intomainfrom
acl/type_wraps_term

Conversation

@acl-cqc
Copy link
Contributor

@acl-cqc acl-cqc commented Feb 25, 2026

  • Merge TypeEnum into Term: remove Term::Runtime(Type), add Term::RuntimeFunction(FuncValueType), Term::RuntimeSum(SumType) and Term::RuntimeExtension(CustomType) and remove TypeEnum. That is, runtime types are now just variants of Term.
  • Type now just wraps a Term, but guarantees by construction that the Term inside it represents a single runtime type. (There is no way to bypass this; there is TryFrom<Term> for Type; there are utility constructors on Type that take Types thus preserving the invariant - the same new_extension, new_tuple, new_sum, new_function as before).
  • Similarly, TypeRowRV wraps a Term, but guarantees it represents a list of types (of perhaps unknown length). That is, it could be a Term::List (whose elements are single types), or a Term::Variable (a "row variable" i.e. ranging over lists of types, of unknown length), or a Term::ListConcat (whose elements are one of these three). Again there are utility constructors preserving the invariant.
    • Note prior to 0ac2b53 (see diff LHS) TypeRowRV was merely an alias to Term (with GeneralSum and FuncValueType providing panicking-new + try_new + new_unchecked constructors, removed in that commit). However I think with a few nifty TypeRowRV conversions and methods (just_row_var and concat) the wrapper-struct is easier to use as well as giving more static checking.
  • TypeRow remains as a list of Types, i.e. whose length/number-of-types is known
  • Remove TypeRV. It never had a consistent meaning: it was sometimes a type, and sometimes a list. Also remove trait MaybeRV, enum NoRV and struct RowVariable.

Thus, although the new system offers less Rust-compile-time checking, there is still a reasonable amount, and it's more principled now ;)

Along the way,

  • Replace Type::as_type_enum with impl Deref<Target=Term> for Type, similarly for TypeRowRV
  • AliasDecl/Defn and Type::Alias dropped for now, pending Overhaul or scrap aliases #2558
  • Introduce a trait Substitutable wrapping the substitute/validate methods, this is used to maintain parametrization of (Poly/)FuncTypeBase over TypeRow or TypeRowRV. Kept hidden as substitute/validate were not public.

TODO/To-consider, reviewers' thoughts requested:

  • I strongly suggest renaming: Term::XXXType -> Term::XXXKind and Term::RuntimeXXX -> Term::XXXType. (Except Term::RuntimeType -> Term::TypeKind.) Unclear whether to do this before/after/in this PR.
  • There's a lot of .map_err(SignatureError::from)? to convert from TermTypeError :(. It is tempting to combine these two errors (at the least, there are a few other constructors in SignatureError that look redundant i.e. also in TermTypeError!)....sadly Rust won't allow impl <T: From<SignatureError>> From<TermTypeError> for T which would make these map_errs go away. Should I do this as a preliminary PR, in here, as a followup?? Any other ideas?
  • Might be better to move caching of TypeBound from Type into SumType::General (via a checked struct - prior to 0ac2b53 there was such, called GeneralSum, so we could reintroduce that and add the bound there). Leaving for now but what do reviewers think?
  • Could add a utility method TypeRowRV::new_spliced(IntoIterator<Item=Term>) that checks each Term is either a type or a list of types (and panics if not....ok could also have try_new_spliced), and then assembles the appropriate lists/concats. Might be a bit easier than the current just_row_var, concat, from([Type]) but would not give as good static (Rust-compile-time) checking....(commit 68fba45 shows this done for FuncValueType whereas here/now it would be for TypeRowRV, i.e. instead of just_row_var/concat). Thoughts?

BREAKING CHANGE: TypeEnum and TypeRV are no more - use Term. RowVariable, MaybeRV etc. are gone - use appropriate term types and variables. Type and TypeRowRV merely wrap Term with invariants.

@acl-cqc acl-cqc changed the title refactor!: combine TypeEnum with Term, remove RV stuff refactor(hugrv2)!: combine TypeEnum with Term, remove RV stuff Feb 25, 2026
@codspeed-hq
Copy link

codspeed-hq bot commented Feb 25, 2026

Merging this PR will degrade performance by 40.19%

❌ 3 regressed benchmarks
✅ 29 untouched benchmarks
⏩ 3 skipped benchmarks1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
construction 12 µs 20 µs -40.19%
circuit_roundtrip/capnp[1000] 74 ms 88.5 ms -16.35%
circuit_roundtrip/capnp[100] 8.4 ms 9.7 ms -13.47%

Comparing acl/type_wraps_term (2962d96) with main (86b654b)

Open in CodSpeed

Footnotes

  1. 3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@codecov
Copy link

codecov bot commented Feb 25, 2026

Codecov Report

❌ Patch coverage is 86.08871% with 138 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.80%. Comparing base (2a40131) to head (2962d96).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
hugr-core/src/types/type_param.rs 83.05% 36 Missing and 4 partials ⚠️
hugr-core/src/import.rs 66.15% 1 Missing and 21 partials ⚠️
hugr-core/src/types.rs 92.66% 5 Missing and 3 partials ⚠️
hugr-core/src/types/check.rs 0.00% 8 Missing ⚠️
hugr-core/src/extension/resolution/types_mut.rs 82.92% 0 Missing and 7 partials ⚠️
hugr-core/src/types/type_row.rs 92.30% 4 Missing and 3 partials ⚠️
hugr-core/src/types/serialize.rs 91.54% 4 Missing and 2 partials ⚠️
hugr-core/src/types/signature.rs 82.35% 6 Missing ⚠️
hugr-core/src/extension/prelude.rs 84.61% 0 Missing and 4 partials ⚠️
hugr-core/src/extension/resolution.rs 33.33% 4 Missing ⚠️
... and 17 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2895      +/-   ##
==========================================
+ Coverage   83.76%   83.80%   +0.04%     
==========================================
  Files         267      266       -1     
  Lines       52594    52953     +359     
  Branches    46533    46892     +359     
==========================================
+ Hits        44053    44379     +326     
+ Misses       6313     6289      -24     
- Partials     2228     2285      +57     
Flag Coverage Δ
python 88.74% <ø> (ø)
rust 83.16% <86.08%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@acl-cqc acl-cqc changed the title refactor(hugrv2)!: combine TypeEnum with Term, remove RV stuff refactor(hugrv2)!: combine TypeEnum with Term, no RV parametrization Feb 25, 2026
@acl-cqc
Copy link
Contributor Author

acl-cqc commented Feb 26, 2026

I imagine the performance is due to extra cloning, although most that I remember was in hugr-llvm (!)...if we can identify which bits are causing the problem these can probably be rewritten using Type::into() -> Term and matching against Term rather than Type::as_sum etc.

Base automatically changed from acl/no_1type_row to main March 11, 2026 17:55
@acl-cqc acl-cqc force-pushed the acl/type_wraps_term branch from 112b608 to 16b4c5e Compare March 13, 2026 11:01
@hugrbot
Copy link
Collaborator

hugrbot commented Mar 13, 2026

This PR contains breaking changes to the public Rust API.

cargo-semver-checks summary
    Building hugr v0.25.7 (current)
     Built [  34.276s] (current)
   Parsing hugr v0.25.7 (current)
    Parsed [   0.004s] (current)
  Building hugr v0.25.7 (baseline)
     Built [  34.707s] (baseline)
   Parsing hugr v0.25.7 (baseline)
    Parsed [   0.004s] (baseline)
  Checking hugr v0.25.7 -> v0.25.7 (assume minor change)
   Checked [   0.013s] 196 checks: 196 pass, 56 skip
   Summary no semver update required
  Finished [  70.170s] hugr
  Building hugr-cli v0.25.7 (current)
     Built [  27.908s] (current)
   Parsing hugr-cli v0.25.7 (current)
    Parsed [   0.006s] (current)
  Building hugr-cli v0.25.7 (baseline)
     Built [  28.076s] (baseline)
   Parsing hugr-cli v0.25.7 (baseline)
    Parsed [   0.006s] (baseline)
  Checking hugr-cli v0.25.7 -> v0.25.7 (assume minor change)
   Checked [   0.016s] 196 checks: 196 pass, 56 skip
   Summary no semver update required
  Finished [  57.158s] hugr-cli
  Building hugr-core v0.25.7 (current)
     Built [  24.447s] (current)
   Parsing hugr-core v0.25.7 (current)
    Parsed [   0.076s] (current)
  Building hugr-core v0.25.7 (baseline)
     Built [  24.796s] (baseline)
   Parsing hugr-core v0.25.7 (baseline)
    Parsed [   0.073s] (baseline)
  Checking hugr-core v0.25.7 -> v0.25.7 (assume minor change)
   Checked [   0.223s] 196 checks: 189 pass, 7 fail, 0 warn, 56 skip

--- failure enum_missing: pub enum removed or renamed ---

Description:
A publicly-visible enum cannot be imported by its prior path. A `pub use` may have been removed, or the enum itself may have been renamed or removed entirely.
      ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
     impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.47.0/src/lints/enum_missing.ron

Failed in:
enum hugr_core::types::TypeEnum, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types.rs:332
enum hugr_core::types::NoRV, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/row_var.rs:55

--- failure enum_variant_missing: pub enum variant removed or renamed ---

Description:
A publicly-visible enum has at least one variant that is no longer available under its prior name. It may have been renamed or removed entirely.
      ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
     impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.47.0/src/lints/enum_variant_missing.ron

Failed in:
variant Term::Runtime, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:100
variant Term::Runtime, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:100
variant Term::Runtime, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:100
variant Term::Runtime, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:100
variant Term::Runtime, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:100
variant SignatureError::RowVarWhereTypeExpected, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/extension.rs:523

--- failure function_requires_different_generic_type_params: function now requires a different number of generic type parameters ---

Description:
A function now requires a different number of generic type parameters than it used to. Uses of this function that supplied the previous number of generic types (e.g. via turbofish syntax) will be broken.
      ref: https://doc.rust-lang.org/reference/items/generics.html
     impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.47.0/src/lints/function_requires_different_generic_type_params.ron

Failed in:
function resolve_type_extensions (1 -> 0 generic types) in /home/runner/work/hugr/hugr/PR_BRANCH/hugr-core/src/extension/resolution.rs:45

--- failure inherent_associated_pub_const_missing: inherent impl's associated pub const removed ---

Description:
An inherent impl's associated public constant is removed or renamed
      ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
     impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.47.0/src/lints/inherent_associated_pub_const_missing.ron

Failed in:
Term::UNIT, previously at /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:284
Term::UNIT, previously at /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:284
Term::UNIT, previously at /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:284
Term::UNIT, previously at /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:284
Term::UNIT, previously at /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:284

--- failure inherent_method_missing: pub method removed or renamed ---

Description:
A publicly-visible method or associated fn is no longer available under its prior name. It may have been renamed or removed entirely.
      ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
     impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.47.0/src/lints/inherent_method_missing.ron

Failed in:
FuncTypeBase::find_rowvar, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/signature.rs:139
SumType::as_unary_option, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types.rs:295
Term::new_list_concat, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:311
Term::as_runtime, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:338
Term::new_list_concat, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:311
Term::as_runtime, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:338
Term::new_list_concat, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:311
Term::as_runtime, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:338
Term::new_list_concat, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:311
Term::as_runtime, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:338
Term::new_list_concat, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:311
Term::as_runtime, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:338

--- failure method_requires_different_generic_type_params: method now requires a different number of generic type parameters ---

Description:
A method now requires a different number of generic type parameters than it used to. Uses of this method that supplied the previous number of generic types will be broken.
      ref: https://doc.rust-lang.org/reference/items/generics.html
     impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.47.0/src/lints/method_requires_different_generic_type_params.ron

Failed in:
hugr_core::extension::resolution::ExtensionCollectionError::dropped_signature takes 0 generic types instead of 1, in /home/runner/work/hugr/hugr/PR_BRANCH/hugr-core/src/extension/resolution.rs:260
hugr_core::extension::resolution::ExtensionCollectionError::dropped_type takes 0 generic types instead of 1, in /home/runner/work/hugr/hugr/PR_BRANCH/hugr-core/src/extension/resolution.rs:271

--- failure struct_missing: pub struct removed or renamed ---

Description:
A publicly-visible struct cannot be imported by its prior path. A `pub use` may have been removed, or the struct itself may have been renamed or removed entirely.
      ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
     impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.47.0/src/lints/struct_missing.ron

Failed in:
struct hugr_core::types::type_param::ListPartIter, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:765
struct hugr_core::types::RowVariable, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/row_var.rs:17
struct hugr_core::types::TypeBase, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types.rs:403
struct hugr_core::types::type_param::TuplePartIter, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_param.rs:800
struct hugr_core::types::type_row::TypeRowBase, previously in file /home/runner/work/hugr/hugr/BASELINE_BRANCH/hugr-core/src/types/type_row.rs:23

   Summary semver requires new major version: 7 major and 0 minor checks failed
  Finished [  50.641s] hugr-core
  Building hugr-llvm v0.25.7 (current)
     Built [  29.370s] (current)
   Parsing hugr-llvm v0.25.7 (current)
    Parsed [   0.012s] (current)
  Building hugr-llvm v0.25.7 (baseline)
     Built [  29.063s] (baseline)
   Parsing hugr-llvm v0.25.7 (baseline)
    Parsed [   0.012s] (baseline)
  Checking hugr-llvm v0.25.7 -> v0.25.7 (assume minor change)
   Checked [   0.043s] 196 checks: 196 pass, 56 skip
   Summary no semver update required
  Finished [  59.825s] hugr-llvm
  Building hugr-model v0.25.7 (current)
     Built [  10.675s] (current)
   Parsing hugr-model v0.25.7 (current)
    Parsed [   0.016s] (current)
  Building hugr-model v0.25.7 (baseline)
     Built [  10.655s] (baseline)
   Parsing hugr-model v0.25.7 (baseline)
    Parsed [   0.015s] (baseline)
  Checking hugr-model v0.25.7 -> v0.25.7 (assume minor change)
   Checked [   0.031s] 196 checks: 196 pass, 56 skip
   Summary no semver update required
  Finished [  22.090s] hugr-model
  Building hugr-passes v0.25.7 (current)
     Built [  26.825s] (current)
   Parsing hugr-passes v0.25.7 (current)
    Parsed [   0.025s] (current)
  Building hugr-passes v0.25.7 (baseline)
     Built [  27.025s] (baseline)
   Parsing hugr-passes v0.25.7 (baseline)
    Parsed [   0.024s] (baseline)
  Checking hugr-passes v0.25.7 -> v0.25.7 (assume minor change)
   Checked [   0.041s] 196 checks: 196 pass, 56 skip
   Summary no semver update required
  Finished [  55.055s] hugr-passes
  Building hugr-persistent v0.4.7 (current)
     Built [  21.485s] (current)
   Parsing hugr-persistent v0.4.7 (current)
    Parsed [   0.008s] (current)
  Building hugr-persistent v0.4.7 (baseline)
     Built [  21.452s] (baseline)
   Parsing hugr-persistent v0.4.7 (baseline)
    Parsed [   0.007s] (baseline)
  Checking hugr-persistent v0.4.7 -> v0.4.7 (assume minor change)
   Checked [   0.014s] 196 checks: 196 pass, 56 skip
   Summary no semver update required
  Finished [  43.753s] hugr-persistent

Term::Tuple(elems) => TermSer::TypeArg(TypeArgSer::Tuple { elems }),
Term::Variable(v) => TermSer::TypeArg(TypeArgSer::Variable { v }),
Term::Variable(v) => {
TermSer::TypeArg(if matches!(&*v.cached_decl, Term::RuntimeType(_)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The need for this complex clause here (it is needed!) only showed up by unexpected changes in the json definition of std_extensions, not any unit test :-(...I'm not sure why

Copy link
Collaborator

@cqc-alec cqc-alec left a comment

Choose a reason for hiding this comment

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

Thanks @acl-cqc . Have had a general look over this and it looks good to me!

Regarding your questions:

  • Does Kind have a technical meaning? What would you rename RuntimeType to? (I guess TypeType?) In any case I think the docstring for Term should be expanded, as its current form ("A term in the language of static parameters in HUGR") is rather unclear, at least to me.
  • Suggest combining these error types, either as a pre- or post-PR (I think this PR is big enough already without adding more changes).
  • Probably worth trying (maybe as a follow-up PR).
  • Seems like a good idea (perhaps as a follow-up PR).

Comment on lines +100 to +101
// or some static version of this?
RuntimeExtension(CustomType),
Copy link
Collaborator

Choose a reason for hiding this comment

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

needs a #[display] incantation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants