Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 49 additions & 4 deletions crates/align_mir/src/canonical_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,10 +515,15 @@ impl<'a> GraphValidator<'a> {
reverse.entry(edge.to).or_default().push(edge.from);
}

// Mark a node when it is entered, not when its siblings are scheduled. Marking every
// child while pushing a whole sibling list can make a shared DAG look cyclic in the
// second pass: a later parent sees its child as already finished even though its finish
// order was never recorded. The entry-time mark also leaves active back-edges for the
// SCC pass, so genuine self and mutual cycles remain rejected.
let mut seen = HashSet::new();
let mut finish = Vec::with_capacity(self.order.len());
for &start in &self.order {
if !seen.insert(start) {
if seen.contains(&start) {
continue;
}
let mut work = vec![(start, false)];
Expand All @@ -527,12 +532,13 @@ impl<'a> GraphValidator<'a> {
finish.push(node);
continue;
}
if !seen.insert(node) {
continue;
}
work.push((node, true));
if let Some(children) = forward.get(&node) {
for &child in children.iter().rev() {
if seen.insert(child) {
work.push((child, false));
}
work.push((child, false));
}
}
}
Expand Down Expand Up @@ -3216,6 +3222,45 @@ mod tests {
);
}

#[test]
fn canonical_graph_allows_shared_inline_dag() {
let mut program = baseline_program();
let field = |name: &str, ty: Ty| align_sema::hir::FieldDef {
name: name.to_string(),
ty,
};
let child = align_sema::hir::StructDef {
name: "Child".to_string(),
source_name: "Child".to_string(),
fields: vec![field("value", Ty::Str)],
align: None,
c_repr: false,
};
let parent = align_sema::hir::StructDef {
name: "Parent".to_string(),
source_name: "Parent".to_string(),
fields: vec![field("child", Ty::Option(Scalar::Struct(1)))],
align: None,
c_repr: false,
};
let root = align_sema::hir::StructDef {
name: "Root".to_string(),
source_name: "Root".to_string(),
fields: vec![
field("nested", Ty::Option(Scalar::Struct(2))),
field("direct", Ty::Option(Scalar::Struct(1))),
],
align: None,
c_repr: false,
};
program.structs = vec![root, child, parent];

assert_eq!(
validate(Ty::Struct(0), &program),
Ok(vec![Node::Struct(0), Node::Struct(2), Node::Struct(1)])
);
}

#[test]
fn canonical_graph_validation_error_precedence() {
let base = baseline_program();
Expand Down
Loading