Skip to content

Commit 1ab5ea7

Browse files
committed
Merge branch 'main' into feat/persistenthugr
2 parents cb812be + 2bfeaae commit 1ab5ea7

File tree

127 files changed

+4041
-3442
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+4041
-3442
lines changed

Cargo.lock

Lines changed: 261 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ rstest = "0.24.0"
6060
semver = "1.0.26"
6161
serde = "1.0.219"
6262
serde_json = "1.0.140"
63+
serde_with = "3.12.0"
6364
serde_yaml = "0.9.34"
6465
smol_str = "0.3.1"
6566
static_assertions = "1.1.0"

hugr-cli/src/hugr_io.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use hugr::envelope::{read_envelope, EnvelopeError};
55
use hugr::extension::ExtensionRegistry;
66
use hugr::package::Package;
77
use hugr::{Extension, Hugr};
8-
use std::io::BufReader;
8+
use std::io::{BufReader, Read};
99
use std::path::PathBuf;
1010

1111
use crate::CliError;
@@ -57,12 +57,23 @@ impl HugrInputArgs {
5757

5858
/// Read a hugr JSON file from the input.
5959
///
60-
/// If [HugrInputArgs::hugr_json] is `false`, [HugrInputArgs::get_package] should be called instead as
61-
/// reading an input envelope as a HUGR json will fail.
60+
/// This is a legacy option for reading old HUGR JSON files when the
61+
/// [HugrInputArgs::hugr_json] flag is used.
62+
///
63+
/// For most cases, [HugrInputArgs::get_package] should be called instead.
6264
pub fn get_hugr(&mut self) -> Result<Hugr, CliError> {
6365
let extensions = self.load_extensions()?;
6466
let mut buffer = BufReader::new(&mut self.input);
65-
let hugr = Hugr::load_json(&mut buffer, &extensions)?;
67+
68+
/// Wraps the hugr JSON so that it defines a valid envelope.
69+
const PREPEND: &str = r#"HUGRiHJv?@{"modules": ["#;
70+
const APPEND: &str = r#"],"extensions": []}"#;
71+
72+
let mut envelope = PREPEND.to_string();
73+
buffer.read_to_string(&mut envelope)?;
74+
envelope.push_str(APPEND);
75+
76+
let hugr = Hugr::load_str(envelope, Some(&extensions))?;
6677
Ok(hugr)
6778
}
6879

hugr-cli/src/lib.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ use clap::{crate_version, Parser};
6060
use clap_verbosity_flag::log::Level;
6161
use clap_verbosity_flag::{InfoLevel, Verbosity};
6262
use hugr::envelope::EnvelopeError;
63-
use hugr::hugr::LoadHugrError;
64-
use hugr::package::{PackageEncodingError, PackageValidationError};
63+
use hugr::package::PackageValidationError;
6564
use std::ffi::OsString;
6665

6766
pub mod extensions;
@@ -97,12 +96,6 @@ pub enum CliError {
9796
/// Error parsing input.
9897
#[display("Error parsing package: {_0}")]
9998
Parse(serde_json::Error),
100-
/// Package load error.
101-
#[display("Error parsing package: {_0}")]
102-
PackageLoad(PackageEncodingError),
103-
/// Hugr load error.
104-
#[display("Error loading hugr: {_0}")]
105-
HugrLoad(LoadHugrError),
10699
#[display("Error validating HUGR: {_0}")]
107100
/// Errors produced by the `validate` subcommand.
108101
Validate(PackageValidationError),

hugr-cli/src/validate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use clap::Parser;
44
use clap_verbosity_flag::log::Level;
55
use hugr::package::PackageValidationError;
6-
use hugr::Hugr;
6+
use hugr::{Hugr, HugrView};
77

88
use crate::hugr_io::HugrInputArgs;
99
use crate::{CliError, OtherArgs};

hugr-cli/tests/validate.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ fn test_package(#[default(bool_t())] id_type: Type) -> Package {
4848
df.finish_with_outputs([i]).unwrap();
4949
let hugr = module.hugr().clone(); // unvalidated
5050

51-
Package::new(vec![hugr]).unwrap()
51+
Package::new(vec![hugr])
5252
}
5353

5454
#[fixture]
@@ -110,30 +110,28 @@ fn bad_hugr_string() -> String {
110110
let df = DFGBuilder::new(Signature::new_endo(vec![qb_t()])).unwrap();
111111
let bad_hugr = df.hugr().clone();
112112

113-
serde_json::to_string(&bad_hugr).unwrap()
113+
bad_hugr.store_str(EnvelopeConfig::text()).unwrap()
114114
}
115115

116116
#[rstest]
117117
fn test_mermaid_invalid(bad_hugr_string: String, mut cmd: Command) {
118118
cmd.arg("mermaid");
119119
cmd.arg("--validate");
120-
cmd.arg("--hugr-json");
121120
cmd.write_stdin(bad_hugr_string);
122121
cmd.assert()
123122
.failure()
124-
.stderr(contains("has an unconnected port"));
123+
.stderr(contains("Error validating HUGR"));
125124
}
126125

127126
#[rstest]
128127
fn test_bad_hugr(bad_hugr_string: String, mut val_cmd: Command) {
129128
val_cmd.write_stdin(bad_hugr_string);
130-
val_cmd.arg("--hugr-json");
131129
val_cmd.arg("-");
132130

133131
val_cmd
134132
.assert()
135133
.failure()
136-
.stderr(contains("Node(1)").and(contains("unconnected port")));
134+
.stderr(contains("Error validating HUGR"));
137135
}
138136

139137
#[rstest]
@@ -195,7 +193,6 @@ fn test_package_validation(package_string: String, mut val_cmd: Command) {
195193
// package with float extension and hugr that uses floats can validate
196194
val_cmd.write_stdin(package_string);
197195
val_cmd.arg("-");
198-
val_cmd.arg("--no-std");
199196

200197
val_cmd.assert().success().stderr(contains(VALID_PRINT));
201198
}

hugr-core/Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@ hugr-model = { version = "0.19.1", path = "../hugr-model" }
3131

3232
cgmath = { workspace = true, features = ["serde"] }
3333
delegate = { workspace = true }
34-
derive_more = { workspace = true, features = ["display", "error", "from"] }
34+
derive_more = { workspace = true, features = [
35+
"display",
36+
"error",
37+
"from",
38+
"into",
39+
] }
3540
downcast-rs = { workspace = true }
3641
enum_dispatch = { workspace = true }
3742
fxhash.workspace = true
@@ -46,6 +51,7 @@ regex = { workspace = true }
4651
# Rc used here for Extension, but unfortunately we must turn the feature on globally
4752
serde = { workspace = true, features = ["derive", "rc"] }
4853
serde_json = { workspace = true }
54+
serde_with = { workspace = true }
4955
serde_yaml = { workspace = true, optional = true }
5056
smol_str = { workspace = true, features = ["serde"] }
5157
static_assertions = { workspace = true }

hugr-core/src/builder.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
//! `CircuitBuilder`.
2727
//!
2828
//! ```rust
29-
//! # use hugr::Hugr;
29+
//! # use hugr::{Hugr, HugrView};
3030
//! # use hugr::builder::{BuildError, BuildHandle, Container, DFGBuilder, Dataflow, DataflowHugr, ModuleBuilder, DataflowSubContainer, HugrBuilder};
3131
//! use hugr::extension::prelude::bool_t;
3232
//! use hugr::std_extensions::logic::{self, LogicOp};
@@ -138,7 +138,7 @@ pub fn inout_sig(inputs: impl Into<TypeRow>, outputs: impl Into<TypeRow>) -> Sig
138138
pub enum BuildError {
139139
/// The constructed HUGR is invalid.
140140
#[error("The constructed HUGR is invalid: {0}.")]
141-
InvalidHUGR(#[from] ValidationError),
141+
InvalidHUGR(#[from] ValidationError<Node>),
142142
/// SignatureError in trying to construct a node (differs from
143143
/// [ValidationError::SignatureError] in that we could not construct a node to report about)
144144
#[error(transparent)]
@@ -151,6 +151,10 @@ pub enum BuildError {
151151
/// CFG can only have one entry.
152152
#[error("CFG entry node already built for CFG node: {0}.")]
153153
EntryBuiltError(Node),
154+
/// We don't allow creating `BasicBlockBuilder<Hugr>`s when the sum-rows
155+
/// are not homogeneous. Use a CFGBuilder and create a valid graph instead.
156+
#[error("Cannot initialize hugr for a BasicBlockBuilder with complex sum-rows. Use a CFGBuilder instead.")]
157+
BasicBlockTooComplex,
154158
/// Node was expected to have a certain type but was found to not.
155159
#[error("Node with index {node} does not have type {op_desc} as expected.")]
156160
#[allow(missing_docs)]
@@ -164,6 +168,13 @@ pub enum BuildError {
164168
#[error("Error building Conditional node: {0}.")]
165169
ConditionalError(#[from] conditional::ConditionalBuildError),
166170

171+
/// Node not found in Hugr
172+
#[error("{node} not found in the Hugr")]
173+
NodeNotFound {
174+
/// Missing node
175+
node: Node,
176+
},
177+
167178
/// Wire not found in Hugr
168179
#[error("Wire not found in Hugr: {0}.")]
169180
WireNotFound(Wire),
@@ -303,31 +314,32 @@ pub(crate) mod test {
303314
#[fixture]
304315
pub(crate) fn simple_package() -> Package {
305316
let hugr = simple_module_hugr();
306-
Package::new([hugr]).unwrap()
317+
Package::new([hugr])
307318
}
308319

309320
#[fixture]
310321
pub(crate) fn multi_module_package() -> Package {
311322
let hugr0 = simple_module_hugr();
312323
let hugr1 = simple_module_hugr();
313-
Package::new([hugr0, hugr1]).unwrap()
324+
Package::new([hugr0, hugr1])
314325
}
315326

316327
/// A helper method which creates a DFG rooted hugr with Input and Output node
317328
/// only (no wires), given a function type with extension delta.
318329
// TODO consider taking two type rows and using TO_BE_INFERRED
319330
pub(crate) fn closed_dfg_root_hugr(signature: Signature) -> Hugr {
320-
let mut hugr = Hugr::new(ops::DFG {
331+
let mut hugr = Hugr::new_with_entrypoint(ops::DFG {
321332
signature: signature.clone(),
322-
});
333+
})
334+
.unwrap();
323335
hugr.add_node_with_parent(
324-
hugr.root(),
336+
hugr.entrypoint(),
325337
ops::Input {
326338
types: signature.input,
327339
},
328340
);
329341
hugr.add_node_with_parent(
330-
hugr.root(),
342+
hugr.entrypoint(),
331343
ops::Output {
332344
types: signature.output,
333345
},

hugr-core/src/builder/build_traits.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ pub trait Container {
9494
name: impl Into<String>,
9595
signature: impl Into<PolyFuncType>,
9696
) -> Result<FunctionBuilder<&mut Hugr>, BuildError> {
97-
let signature = signature.into();
97+
let signature: PolyFuncType = signature.into();
9898
let body = signature.body().clone();
9999
let f_node = self.add_child_node(ops::FuncDefn {
100100
name: name.into(),
@@ -161,7 +161,7 @@ pub trait Container {
161161
/// (with varying root node types)
162162
pub trait HugrBuilder: Container {
163163
/// Finish building the HUGR, perform any validation checks and return it.
164-
fn finish_hugr(self) -> Result<Hugr, ValidationError>;
164+
fn finish_hugr(self) -> Result<Hugr, ValidationError<Node>>;
165165
}
166166

167167
/// Types implementing this trait build a container graph region by borrowing a HUGR
@@ -228,9 +228,9 @@ pub trait Dataflow: Container {
228228
hugr: Hugr,
229229
input_wires: impl IntoIterator<Item = Wire>,
230230
) -> Result<BuildHandle<DataflowOpID>, BuildError> {
231-
let optype = hugr.get_optype(hugr.root()).clone();
231+
let optype = hugr.get_optype(hugr.entrypoint()).clone();
232232
let num_outputs = optype.value_output_count();
233-
let node = self.add_hugr(hugr).new_root;
233+
let node = self.add_hugr(hugr).inserted_entrypoint;
234234

235235
wire_up_inputs(input_wires, node, self)
236236
.map_err(|error| BuildError::OperationWiring { op: optype, error })?;
@@ -250,8 +250,8 @@ pub trait Dataflow: Container {
250250
hugr: &impl HugrView,
251251
input_wires: impl IntoIterator<Item = Wire>,
252252
) -> Result<BuildHandle<DataflowOpID>, BuildError> {
253-
let node = self.add_hugr_view(hugr).new_root;
254-
let optype = hugr.get_optype(hugr.root()).clone();
253+
let node = self.add_hugr_view(hugr).inserted_entrypoint;
254+
let optype = hugr.get_optype(hugr.entrypoint()).clone();
255255
let num_outputs = optype.value_output_count();
256256

257257
wire_up_inputs(input_wires, node, self)
@@ -284,6 +284,7 @@ pub trait Dataflow: Container {
284284
/// # Panics
285285
///
286286
/// Panics if the number of input Wires does not match the size of the array.
287+
#[track_caller]
287288
fn input_wires_arr<const N: usize>(&self) -> [Wire; N] {
288289
collect_array(self.input_wires())
289290
}
@@ -676,7 +677,7 @@ fn add_node_with_wires<T: Dataflow + ?Sized>(
676677
nodetype: impl Into<OpType>,
677678
inputs: impl IntoIterator<Item = Wire>,
678679
) -> Result<(Node, usize), BuildError> {
679-
let op = nodetype.into();
680+
let op: OpType = nodetype.into();
680681
let num_outputs = op.value_output_count();
681682
let op_node = data_builder.add_child_node(op.clone());
682683

0 commit comments

Comments
 (0)