Skip to content

Commit

Permalink
feat!: Don't require explicit extension registers for validation (#1784)
Browse files Browse the repository at this point in the history
Now that we keep references to the extensions used around the hugr, we
no longer need to pass `ExtensionRegistry`es when calling `validate` on
ops, types, etc. This PR removes most uses of the registries.

drive-by: Fix `Noop` not declaring its type argument in `hugr-py`.

Closes #1774; now that the type carries its extension we can instantiate
`Array`s with any element type.

BREAKING CHANGE: Removed the extension registry argument from `validate`
calls.
BREAKING CHANGE: Removed the extension registry argument from operation
instantiation methods.
BREAKING CHANGE: Removed most extension-specific test registries. Use
`EMPTY_REG`, `PRELUDE_REGISTRY`, or `STD_REG` instead.
  • Loading branch information
aborgna-q authored Dec 16, 2024
1 parent 1091755 commit b517dc3
Show file tree
Hide file tree
Showing 56 changed files with 402 additions and 642 deletions.
6 changes: 3 additions & 3 deletions hugr-core/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
//! # use hugr::Hugr;
//! # use hugr::builder::{BuildError, BuildHandle, Container, DFGBuilder, Dataflow, DataflowHugr, ModuleBuilder, DataflowSubContainer, HugrBuilder};
//! use hugr::extension::prelude::bool_t;
//! use hugr::std_extensions::logic::{EXTENSION_ID, LOGIC_REG, LogicOp};
//! use hugr::std_extensions::logic::{self, LogicOp};
//! use hugr::types::Signature;
//!
//! # fn doctest() -> Result<(), BuildError> {
Expand All @@ -42,7 +42,7 @@
//! let _dfg_handle = {
//! let mut dfg = module_builder.define_function(
//! "main",
//! Signature::new_endo(bool_t()).with_extension_delta(EXTENSION_ID),
//! Signature::new_endo(bool_t()).with_extension_delta(logic::EXTENSION_ID),
//! )?;
//!
//! // Get the wires from the function inputs.
Expand All @@ -60,7 +60,7 @@
//! let mut dfg = module_builder.define_function(
//! "circuit",
//! Signature::new_endo(vec![bool_t(), bool_t()])
//! .with_extension_delta(EXTENSION_ID),
//! .with_extension_delta(logic::EXTENSION_ID),
//! )?;
//! let mut circuit = dfg.as_circuit(dfg.input_wires());
//!
Expand Down
5 changes: 2 additions & 3 deletions hugr-core/src/builder/build_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ pub trait Dataflow: Container {
};

let load_n = self.add_dataflow_op(
ops::LoadFunction::try_new(func_sig, type_args, self.hugr().extensions())?,
ops::LoadFunction::try_new(func_sig, type_args)?,
// Static wire from the function node
vec![Wire::new(func_node, func_op.static_output_port().unwrap())],
)?;
Expand Down Expand Up @@ -699,8 +699,7 @@ pub trait Dataflow: Container {
})
}
};
let op: OpType =
ops::Call::try_new(type_scheme, type_args, self.hugr().extensions())?.into();
let op: OpType = ops::Call::try_new(type_scheme, type_args)?.into();
let const_in_port = op.static_input_port().unwrap();
let op_id = self.add_dataflow_op(op, input_wires)?;
let src_port = self.hugr_mut().num_outputs(function.node()) - 1;
Expand Down
6 changes: 2 additions & 4 deletions hugr-core/src/builder/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ mod test {

use crate::builder::{Container, HugrBuilder, ModuleBuilder};
use crate::extension::prelude::{qb_t, usize_t};
use crate::extension::{ExtensionId, ExtensionSet, PRELUDE_REGISTRY};
use crate::extension::{ExtensionId, ExtensionSet};
use crate::std_extensions::arithmetic::float_types::{self, ConstF64};
use crate::utils::test_quantum_extension::{
self, cx_gate, h_gate, measure, q_alloc, q_discard, rz_f64,
Expand Down Expand Up @@ -305,9 +305,7 @@ mod test {
)
.unwrap();
});
let my_custom_op = my_ext
.instantiate_extension_op("MyOp", [], &PRELUDE_REGISTRY)
.unwrap();
let my_custom_op = my_ext.instantiate_extension_op("MyOp", []).unwrap();

let mut module_builder = ModuleBuilder::new();
let mut f_build = module_builder
Expand Down
3 changes: 1 addition & 2 deletions hugr-core/src/builder/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ pub(crate) mod test {
};
use crate::extension::prelude::{bool_t, qb_t, usize_t};
use crate::extension::prelude::{Lift, Noop};
use crate::extension::{ExtensionId, SignatureError, PRELUDE_REGISTRY};
use crate::extension::{ExtensionId, SignatureError};
use crate::hugr::validate::InterGraphEdgeError;
use crate::ops::{handle::NodeHandle, OpTag};
use crate::ops::{OpTrait, Value};
Expand Down Expand Up @@ -656,7 +656,6 @@ pub(crate) mod test {
let ev = e.instantiate_extension_op(
"eval",
[vec![usize_t().into()].into(), vec![tv.into()].into()],
&PRELUDE_REGISTRY,
);
assert_eq!(
ev,
Expand Down
32 changes: 9 additions & 23 deletions hugr-core/src/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,20 +113,13 @@ impl ExtensionRegistry {
self.exts.contains_key(name)
}

/// Validate the set of extensions, ensuring that each extension requirements are also in the registry.
///
/// Note this potentially asks extensions to validate themselves against other extensions that
/// may *not* be valid themselves yet. It'd be better to order these respecting dependencies,
/// or at least to validate the types first - which we don't do at all yet:
//
// TODO https://github.com/CQCL/hugr/issues/624. However, parametrized types could be
// cyclically dependent, so there is no perfect solution, and this is at least simple.
/// Validate the set of extensions.
pub fn validate(&self) -> Result<(), ExtensionRegistryError> {
if self.valid.load(Ordering::Relaxed) {
return Ok(());
}
for ext in self.exts.values() {
ext.validate(self)
ext.validate()
.map_err(|e| ExtensionRegistryError::InvalidSignature(ext.name().clone(), e))?;
}
self.valid.store(true, Ordering::Relaxed);
Expand Down Expand Up @@ -398,14 +391,9 @@ pub enum SignatureError {
/// Invalid type arguments
#[error("Invalid type arguments for operation")]
InvalidTypeArgs,
/// The Extension Registry did not contain an Extension referenced by the Signature
#[error("Extension '{missing}' is not part of the declared HUGR extensions [{}]",
available.iter().map(|e| e.to_string()).collect::<Vec<_>>().join(", ")
)]
ExtensionNotFound {
missing: ExtensionId,
available: Vec<ExtensionId>,
},
/// The weak [`Extension`] reference for a custom type has been dropped.
#[error("Type '{typ}' is defined in extension '{missing}', but the extension reference has been dropped.")]
MissingTypeExtension { typ: TypeName, missing: ExtensionId },
/// The Extension was found in the registry, but did not contain the Type(Def) referenced in the Signature
#[error("Extension '{exn}' did not contain expected TypeDef '{typ}'")]
ExtensionTypeNotFound { exn: ExtensionId, typ: TypeName },
Expand Down Expand Up @@ -740,18 +728,16 @@ impl Extension {
&self,
name: &OpNameRef,
args: impl Into<Vec<TypeArg>>,
ext_reg: &ExtensionRegistry,
) -> Result<ExtensionOp, SignatureError> {
let op_def = self.get_op(name).expect("Op not found.");
ExtensionOp::new(op_def.clone(), args, ext_reg)
ExtensionOp::new(op_def.clone(), args)
}

/// Validates against a registry, which we can assume includes this extension itself.
// (TODO deal with the registry itself containing invalid extensions!)
fn validate(&self, all_exts: &ExtensionRegistry) -> Result<(), SignatureError> {
/// Validates the operation definitions in the register.
fn validate(&self) -> Result<(), SignatureError> {
// We should validate TypeParams of TypeDefs too - https://github.com/CQCL/hugr/issues/624
for op_def in self.operations.values() {
op_def.validate(all_exts)?;
op_def.validate()?;
}
Ok(())
}
Expand Down
4 changes: 2 additions & 2 deletions hugr-core/src/extension/declarative.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
//! # const DECLARATIVE_YAML: &str = include_str!("../../examples/extension/declarative.yaml");
//! # use hugr::extension::declarative::load_extensions;
//! // Required extensions must already be present in the registry.
//! let mut reg = hugr::std_extensions::logic::LOGIC_REG.clone();
//! let mut reg = hugr::std_extensions::STD_REG.clone();
//! load_extensions(DECLARATIVE_YAML, &mut reg).unwrap();
//! ```
//!
Expand Down Expand Up @@ -364,7 +364,7 @@ extensions:

#[cfg_attr(miri, ignore)] // Opening files is not supported in (isolated) miri
#[rstest]
#[case(EXAMPLE_YAML_FILE, 1, 1, 3, &std_extensions::logic::LOGIC_REG)]
#[case(EXAMPLE_YAML_FILE, 1, 1, 3, &std_extensions::STD_REG)]
fn test_decode_file(
#[case] yaml_file: &str,
#[case] num_declarations: usize,
Expand Down
Loading

0 comments on commit b517dc3

Please sign in to comment.