Skip to content

Commit

Permalink
feat: Make the rewrite errors more useful
Browse files Browse the repository at this point in the history
  • Loading branch information
aborgna-q committed Jun 7, 2024
1 parent 1cdaeed commit 1a56ed5
Showing 1 changed file with 69 additions and 16 deletions.
85 changes: 69 additions & 16 deletions hugr-core/src/hugr/views/sibling_subgraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::builder::{Container, FunctionBuilder};
use crate::hugr::{HugrMut, HugrView, RootTagged};
use crate::ops::dataflow::DataflowOpTrait;
use crate::ops::handle::{ContainerHandle, DataflowOpID};
use crate::ops::{OpTag, OpTrait};
use crate::ops::{NamedOp, OpTag, OpTrait, OpType};
use crate::types::{FunctionType, Type};
use crate::{Hugr, IncomingPort, Node, OutgoingPort, Port, SimpleReplacement};

Expand Down Expand Up @@ -340,13 +340,22 @@ impl SiblingSubgraph {
let rep_root = replacement.root();
let dfg_optype = replacement.get_optype(rep_root);
if !OpTag::Dfg.is_superset(dfg_optype.tag()) {
return Err(InvalidReplacement::InvalidDataflowGraph);
return Err(InvalidReplacement::InvalidDataflowGraph {
node: rep_root,
op: dfg_optype.clone(),
});
}
let Some([rep_input, rep_output]) = replacement.get_io(rep_root) else {
return Err(InvalidReplacement::InvalidDataflowParent);
return Err(InvalidReplacement::InvalidDataflowParent {
node: rep_root,
op: dfg_optype.clone(),
});
};
if dfg_optype.dataflow_signature() != Some(self.signature(hugr)) {
return Err(InvalidReplacement::InvalidSignature);
return Err(InvalidReplacement::InvalidSignature {
expected: self.signature(hugr),
actual: dfg_optype.dataflow_signature(),
});
}

// TODO: handle state order edges. For now panic if any are present.
Expand Down Expand Up @@ -503,7 +512,20 @@ fn validate_subgraph<H: HugrView>(
}
// Check all nodes share parent
if !nodes.iter().map(|&n| hugr.get_parent(n)).all_equal() {
return Err(InvalidSubgraph::NoSharedParent);
let first_node = nodes[0];
let first_parent = hugr.get_parent(first_node);
let other_node = *nodes
.iter()
.skip(1)
.find(|&&n| hugr.get_parent(n) != first_parent)
.unwrap();
let other_parent = hugr.get_parent(other_node);
return Err(InvalidSubgraph::NoSharedParent {
first_node,
first_parent,
other_node,
other_parent,
});
}

// Check there are no linked "other" ports
Expand Down Expand Up @@ -624,18 +646,36 @@ fn has_other_edge<H: HugrView>(hugr: &H, node: Node, dir: Direction) -> bool {
}

/// Errors that can occur while constructing a [`SimpleReplacement`].
#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[derive(Debug, Clone, PartialEq, Error)]
#[non_exhaustive]
pub enum InvalidReplacement {
/// No DataflowParent root in replacement graph.
#[error("No DataflowParent root in replacement graph.")]
InvalidDataflowGraph,
#[error("The root of the replacement {node} is a {}, but only OpType::DFGs are supported.", op.name())]
InvalidDataflowGraph {
/// The node ID of the root node.
node: Node,
/// The op type of the root node.
op: OpType,
},
/// Malformed DataflowParent in replacement graph.
#[error("Malformed DataflowParent in replacement graph.")]
InvalidDataflowParent,
#[error("The root of the replacement {node} is malformed. It is a {} but does not contain I/O nodes.", op.name())]
InvalidDataflowParent {
/// The node ID of the root node.
node: Node,
/// The op type of the root node.
op: OpType,
},
/// Replacement graph boundary size mismatch.
#[error("Replacement graph boundary size mismatch.")]
InvalidSignature,
#[error(
"Replacement graph boundary size mismatch. Expected {expected}, got {}.",
actual.clone().map_or("none".to_string(), |t| t.to_string()))
]
InvalidSignature {
/// The expected signature.
expected: FunctionType,
/// The actual signature.
actual: Option<FunctionType>,
},
/// SiblingSubgraph is not convex.
#[error("SiblingSubgraph is not convex.")]
NonConvexSubgraph,
Expand All @@ -649,8 +689,21 @@ pub enum InvalidSubgraph {
#[error("The subgraph is not convex.")]
NotConvex,
/// Not all nodes have the same parent.
#[error("Not a sibling subgraph.")]
NoSharedParent,
#[error(
"Invalid sibling subgraph. {first_node} has parent {}, but {other_node} has parent {}.",
first_parent.map_or("None".to_string(), |n| n.to_string()),
other_parent.map_or("None".to_string(), |n| n.to_string())
)]
NoSharedParent {
/// The first node.
first_node: Node,
/// The parent of the first node.
first_parent: Option<Node>,
/// The other node.
other_node: Node,
/// The parent of the other node.
other_parent: Option<Node>,
},
/// Empty subgraphs are not supported.
#[error("Empty subgraphs are not supported.")]
EmptySubgraph,
Expand Down Expand Up @@ -849,9 +902,9 @@ mod tests {
builder.finish_prelude_hugr_with_outputs(inputs).unwrap()
};

assert_eq!(
assert_matches!(
sub.create_simple_replacement(&func, empty_dfg).unwrap_err(),
InvalidReplacement::InvalidSignature
InvalidReplacement::InvalidSignature { .. }
);
Ok(())
}
Expand Down

0 comments on commit 1a56ed5

Please sign in to comment.