Skip to content

Commit 5b90887

Browse files
committed
Verify no duplicate exports/imports (and none except at top)
1 parent f513a96 commit 5b90887

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed

hugr-core/src/hugr/validate.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! HUGR invariant checks.
22
3+
use std::collections::hash_map::Entry;
34
use std::collections::HashMap;
45
use std::iter;
56

@@ -299,6 +300,39 @@ impl<'a, H: HugrView> ValidationContext<'a, H> {
299300
});
300301
}
301302
}
303+
304+
// Linking info
305+
let mut node_and_imp_sig = HashMap::new();
306+
for c in all_children.clone() {
307+
let (link_name, imp_sig) = match self.hugr.get_optype(c) {
308+
OpType::FuncDecl(fd) => (&fd.name, Some(&fd.signature)),
309+
OpType::FuncDefn(fd) => match fd.link_name.as_ref() {
310+
Some(ln) => (ln, None),
311+
None => continue,
312+
},
313+
_ => continue,
314+
};
315+
if node != self.hugr.module_root() {
316+
return Err(ValidationError::LinkNameNotAtTopLevel { node: c });
317+
}
318+
match node_and_imp_sig.entry(link_name) {
319+
Entry::Vacant(ve) => {
320+
ve.insert((c, imp_sig));
321+
}
322+
Entry::Occupied(oe) => {
323+
// Two nodes. Iff both import the same sig then we're OK
324+
let (prev_c, prev_imp_sig) = oe.get();
325+
if prev_imp_sig != &imp_sig || prev_imp_sig.is_none() {
326+
// Either they are different (import<->export, or import signature), or both are exports
327+
return Err(ValidationError::DuplicateExternalNames {
328+
link_name: link_name.clone(),
329+
children: [*prev_c, c],
330+
});
331+
};
332+
}
333+
}
334+
}
335+
302336
// Additional validations running over the full list of children optypes
303337
let children_optypes = all_children.map(|c| (c, self.hugr.get_optype(c)));
304338
if let Err(source) = op_type.validate_op_children(children_optypes) {
@@ -657,6 +691,21 @@ pub enum ValidationError<N: HugrNode> {
657691
parent_optype: OpType,
658692
source: ChildrenValidationError<N>,
659693
},
694+
/// Multiple nodes were exported using the same name from a [Module](super::Module)
695+
#[error("FuncDefn is exported under same name {link_name} as earlier node {:?}", children[0])]
696+
DuplicateExternalNames {
697+
/// The link_name of a [FuncDecl] or [FuncDefn](super::FuncDefn)
698+
link_name: String,
699+
/// Two nodes node exported under that name
700+
children: [N; 2],
701+
},
702+
/// A [FuncDecl], or `FuncDefn` with a [link_name](super::FuncDefn::link_name),
703+
/// was neither root nor child of a [Module] root
704+
#[error("Node {node} has a link_name but is neither root nor child of Module root")]
705+
LinkNameNotAtTopLevel {
706+
// The node exporting/importing the name
707+
node: N,
708+
},
660709
/// The children graph has invalid edges.
661710
#[error(
662711
"An operation {parent_optype} contains invalid edges between its children: {source}. In parent {parent}, edge from {from:?} port {from_port:?} to {to:?} port {to_port:?}",

0 commit comments

Comments
 (0)