diff --git a/quantinuum-hugr/src/extension.rs b/quantinuum-hugr/src/extension.rs index 34ed3e44c..578d893a7 100644 --- a/quantinuum-hugr/src/extension.rs +++ b/quantinuum-hugr/src/extension.rs @@ -492,7 +492,7 @@ impl ExtensionSet { .try_for_each(|var_idx| check_typevar_decl(params, var_idx, &TypeParam::Extensions)) } - pub(crate) fn substitute(&self, t: &impl Substitution) -> Self { + pub(crate) fn substitute(&self, t: &Substitution) -> Self { Self::from_iter(self.0.iter().flat_map(|e| match as_typevar(e) { None => vec![e.clone()], Some(i) => match t.apply_var(i, &TypeParam::Extensions) { diff --git a/quantinuum-hugr/src/types.rs b/quantinuum-hugr/src/types.rs index 00efc358d..38fe77c48 100644 --- a/quantinuum-hugr/src/types.rs +++ b/quantinuum-hugr/src/types.rs @@ -9,6 +9,7 @@ pub mod type_param; pub mod type_row; pub use crate::ops::constant::{ConstTypeError, CustomCheckFailure}; +use crate::types::type_param::check_type_arg; use crate::utils::display_list_with_separator; pub use check::SumTypeError; pub use custom::CustomType; @@ -357,10 +358,15 @@ impl Type { } } - pub(crate) fn substitute(&self, t: &impl Substitution) -> Self { + pub(crate) fn substitute(&self, t: &Substitution) -> Self { match &self.0 { TypeEnum::Alias(_) | TypeEnum::Sum(SumType::Unit { .. }) => self.clone(), - TypeEnum::Variable(idx, bound) => t.apply_typevar(*idx, *bound), + TypeEnum::Variable(idx, bound) => { + let TypeArg::Type { ty } = t.apply_var(*idx, &((*bound).into())) else { + panic!("Variable was not a type - try validate() first") + }; + ty + } TypeEnum::Extension(cty) => Type::new_extension(cty.substitute(t)), TypeEnum::Function(bf) => Type::new_function(bf.substitute(t)), TypeEnum::Sum(SumType::General { rows }) => { @@ -370,26 +376,26 @@ impl Type { } } -/// A function that replaces type variables with values. -/// (The values depend upon the implementation, to allow dynamic computation; -/// and [Substitution] deals only with type variables, other/containing types/typeargs -/// are handled by [Type::substitute], [TypeArg::substitute] and friends.) -pub(crate) trait Substitution { - /// Apply to a variable of kind [TypeParam::Type] - fn apply_typevar(&self, idx: usize, bound: TypeBound) -> Type { - let TypeArg::Type { ty } = self.apply_var(idx, &bound.into()) else { - panic!("Variable was not a type - try validate() first") - }; - ty +/// Details a replacement of type variables with a finite list of known values. +/// (Variables out of the range of the list will result in a panic) +pub(crate) struct Substitution<'a>(&'a [TypeArg], &'a ExtensionRegistry); + +impl<'a> Substitution<'a> { + pub(crate) fn apply_var(&self, idx: usize, decl: &TypeParam) -> TypeArg { + let arg = self + .0 + .get(idx) + .expect("Undeclared type variable - call validate() ?"); + debug_assert_eq!(check_type_arg(arg, decl), Ok(())); + arg.clone() } - /// Apply to a variable whose kind is any given [TypeParam] - fn apply_var(&self, idx: usize, decl: &TypeParam) -> TypeArg; - - fn extension_registry(&self) -> &ExtensionRegistry; + fn extension_registry(&self) -> &ExtensionRegistry { + self.1 + } } -fn subst_row(row: &TypeRow, tr: &impl Substitution) -> TypeRow { +fn subst_row(row: &TypeRow, tr: &Substitution) -> TypeRow { let res = row .iter() .map(|ty| ty.substitute(tr)) diff --git a/quantinuum-hugr/src/types/custom.rs b/quantinuum-hugr/src/types/custom.rs index ba738227a..e575bdf3f 100644 --- a/quantinuum-hugr/src/types/custom.rs +++ b/quantinuum-hugr/src/types/custom.rs @@ -88,7 +88,7 @@ impl CustomType { }) } - pub(super) fn substitute(&self, tr: &impl Substitution) -> Self { + pub(super) fn substitute(&self, tr: &Substitution) -> Self { let args = self .args .iter() diff --git a/quantinuum-hugr/src/types/poly_func.rs b/quantinuum-hugr/src/types/poly_func.rs index 5f4c3f3f8..3e3ec224b 100644 --- a/quantinuum-hugr/src/types/poly_func.rs +++ b/quantinuum-hugr/src/types/poly_func.rs @@ -1,9 +1,6 @@ //! Polymorphic Function Types -use crate::{ - extension::{ExtensionRegistry, SignatureError}, - types::type_param::check_type_arg, -}; +use crate::extension::{ExtensionRegistry, SignatureError}; use itertools::Itertools; use super::type_param::{check_type_args, TypeArg, TypeParam}; @@ -111,26 +108,7 @@ impl PolyFuncType { // Check that args are applicable, and that we have a value for each binder, // i.e. each possible free variable within the body. check_type_args(args, &self.params)?; - Ok(self.body.substitute(&SubstValues(args, ext_reg))) - } -} - -/// A [Substitution] with a finite list of known values. -/// (Variables out of the range of the list will result in a panic) -struct SubstValues<'a>(&'a [TypeArg], &'a ExtensionRegistry); - -impl<'a> Substitution for SubstValues<'a> { - fn apply_var(&self, idx: usize, decl: &TypeParam) -> TypeArg { - let arg = self - .0 - .get(idx) - .expect("Undeclared type variable - call validate() ?"); - debug_assert_eq!(check_type_arg(arg, decl), Ok(())); - arg.clone() - } - - fn extension_registry(&self) -> &ExtensionRegistry { - self.1 + Ok(self.body.substitute(&Substitution(args, ext_reg))) } } diff --git a/quantinuum-hugr/src/types/signature.rs b/quantinuum-hugr/src/types/signature.rs index 38641f13c..97361cb52 100644 --- a/quantinuum-hugr/src/types/signature.rs +++ b/quantinuum-hugr/src/types/signature.rs @@ -41,7 +41,7 @@ impl FunctionType { self.extension_reqs.validate(var_decls) } - pub(crate) fn substitute(&self, tr: &impl Substitution) -> Self { + pub(crate) fn substitute(&self, tr: &Substitution) -> Self { FunctionType { input: subst_row(&self.input, tr), output: subst_row(&self.output, tr), diff --git a/quantinuum-hugr/src/types/type_param.rs b/quantinuum-hugr/src/types/type_param.rs index e6d90a249..acba60844 100644 --- a/quantinuum-hugr/src/types/type_param.rs +++ b/quantinuum-hugr/src/types/type_param.rs @@ -224,7 +224,7 @@ impl TypeArg { } } - pub(crate) fn substitute(&self, t: &impl Substitution) -> Self { + pub(crate) fn substitute(&self, t: &Substitution) -> Self { match self { TypeArg::Type { ty } => TypeArg::Type { ty: ty.substitute(t),