[DEV-8000] ir::asg: Introduce SortableAsgError

This will be used for the next commit, but this change has been isolated
both because it distracts from the implementation change in the next commit,
and because it cleans up the code by removing the need for a type parameter
on `AsgError`.

Note that the sort test cases now use `unwrap` instead of having
`{,Sortable}AsgError` support one or the other---this is because that does
not currently happen in practice, and there is not supposed to be a
hierarchy; they are siblings (though perhaps their name may imply otherwise).
master
Mike Gerwitz 2020-07-01 13:38:01 -04:00
parent f832feb3fa
commit 0d4bbe5e4e
5 changed files with 436 additions and 307 deletions

View File

@ -20,7 +20,8 @@
//! Base concrete [`Asg`] implementation.
use super::graph::{
Asg, AsgEdge, AsgError, AsgResult, IndexType, Node, ObjectRef, SortableAsg,
Asg, AsgEdge, AsgResult, IndexType, Node, ObjectRef, SortableAsg,
SortableAsgError, SortableAsgResult,
};
use super::ident::IdentKind;
use super::object::{
@ -158,7 +159,7 @@ where
&mut self,
name: &'i Symbol<'i>,
f: F,
) -> AsgResult<ObjectRef<Ix>, Ix>
) -> AsgResult<ObjectRef<Ix>>
where
F: FnOnce(O) -> TransitionResult<O>,
{
@ -177,7 +178,7 @@ where
&mut self,
identi: ObjectRef<Ix>,
f: F,
) -> AsgResult<ObjectRef<Ix>, Ix>
) -> AsgResult<ObjectRef<Ix>>
where
F: FnOnce(O) -> TransitionResult<O>,
{
@ -209,7 +210,7 @@ where
name: &'i Symbol<'i>,
kind: IdentKind,
src: Source<'i>,
) -> AsgResult<ObjectRef<Ix>, Ix> {
) -> AsgResult<ObjectRef<Ix>> {
self.with_ident_lookup(name, |obj| obj.resolve(kind, src))
}
@ -218,7 +219,7 @@ where
name: &'i Symbol<'i>,
kind: IdentKind,
src: Source<'i>,
) -> AsgResult<ObjectRef<Ix>, Ix> {
) -> AsgResult<ObjectRef<Ix>> {
self.with_ident_lookup(name, |obj| obj.extern_(kind, src))
}
@ -226,7 +227,7 @@ where
&mut self,
identi: ObjectRef<Ix>,
text: FragmentText,
) -> AsgResult<ObjectRef<Ix>, Ix> {
) -> AsgResult<ObjectRef<Ix>> {
self.with_ident(identi, |obj| obj.set_fragment(text))
}
@ -281,7 +282,7 @@ where
fn sort(
&'i self,
roots: &[ObjectRef<Ix>],
) -> AsgResult<Sections<'i, O>, Ix> {
) -> SortableAsgResult<Sections<'i, O>, Ix> {
let mut deps = Sections::new();
check_cycles(self)?;
@ -312,10 +313,13 @@ where
_ => deps.rater.push_body(ident),
},
None => {
return Err(AsgError::UnexpectedNode(format!(
"{:?}",
ident.as_ident()
)))
return Err(SortableAsgError::MissingObjectKind(
ident
.name()
.map(|name| name.as_ref())
.unwrap_or("<unknown>")
.into(),
))
}
}
}
@ -332,7 +336,7 @@ where
///
/// We loop through all SCCs and check that they are not all functions. If
/// they are, we ignore the cycle, otherwise we will return an error.
fn check_cycles<'i, O, Ix>(asg: &BaseAsg<O, Ix>) -> AsgResult<(), Ix>
fn check_cycles<'i, O, Ix>(asg: &BaseAsg<O, Ix>) -> SortableAsgResult<(), Ix>
where
Ix: IndexType,
O: IdentObjectData<'i> + IdentObjectState<'i, O>,
@ -374,7 +378,7 @@ where
if cycles.is_empty() {
Ok(())
} else {
Err(AsgError::Cycles(cycles))
Err(SortableAsgError::Cycles(cycles))
}
}
@ -488,7 +492,7 @@ mod test {
}
#[test]
fn declare_new_unique_idents() -> AsgResult<(), u8> {
fn declare_new_unique_idents() -> AsgResult<()> {
let mut sut = Sut::new();
// NB: The index ordering is important! We first use a larger
@ -546,7 +550,7 @@ mod test {
}
#[test]
fn lookup_by_symbol() -> AsgResult<(), u8> {
fn lookup_by_symbol() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "lookup");
@ -565,7 +569,7 @@ mod test {
}
#[test]
fn declare_returns_existing() -> AsgResult<(), u8> {
fn declare_returns_existing() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "symdup");
@ -591,7 +595,7 @@ mod test {
// Builds upon declare_returns_existing.
#[test]
fn declare_fails_if_transition_fails() -> AsgResult<(), u8> {
fn declare_fails_if_transition_fails() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "symdup");
@ -627,7 +631,7 @@ mod test {
}
#[test]
fn declare_extern_returns_existing() -> AsgResult<(), u8> {
fn declare_extern_returns_existing() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "symext");
@ -653,7 +657,7 @@ mod test {
// Builds upon declare_returns_existing.
#[test]
fn declare_extern_fails_if_transition_fails() -> AsgResult<(), u8> {
fn declare_extern_fails_if_transition_fails() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "symdup");
@ -693,7 +697,7 @@ mod test {
}
#[test]
fn add_fragment_to_ident() -> AsgResult<(), u8> {
fn add_fragment_to_ident() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "tofrag");
@ -723,7 +727,7 @@ mod test {
}
#[test]
fn add_fragment_to_ident_fails_if_transition_fails() -> AsgResult<(), u8> {
fn add_fragment_to_ident_fails_if_transition_fails() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "failfrag");
@ -757,7 +761,7 @@ mod test {
}
#[test]
fn add_ident_dep_to_ident() -> AsgResult<(), u8> {
fn add_ident_dep_to_ident() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "sym");
@ -778,7 +782,7 @@ mod test {
// same as above test
#[test]
fn add_dep_lookup_existing() -> AsgResult<(), u8> {
fn add_dep_lookup_existing() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "sym");
@ -794,7 +798,7 @@ mod test {
}
#[test]
fn add_dep_lookup_missing() -> AsgResult<(), u8> {
fn add_dep_lookup_missing() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "sym");
@ -811,7 +815,7 @@ mod test {
}
#[test]
fn declare_return_missing_symbol() -> AsgResult<(), u8> {
fn declare_return_missing_symbol() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "sym");
@ -859,7 +863,7 @@ mod test {
let sym = symbol_dummy!(i, stringify!($name));
$sut.declare(&sym, $kind, Source::default())?;
$sut.declare(&sym, $kind, Source::default()).unwrap();
let (_, _) = $sut.add_dep_lookup($base, &sym);
$dest.push(sym);
@ -868,7 +872,7 @@ mod test {
}
#[test]
fn graph_sort() -> AsgResult<(), u8> {
fn graph_sort() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let mut meta = vec![];
@ -877,8 +881,9 @@ mod test {
let mut retmap = vec![];
let base = symbol_dummy!(1, "sym1");
let base_node =
sut.declare(&base, IdentKind::Map, Source::default())?;
let base_node = sut
.declare(&base, IdentKind::Map, Source::default())
.unwrap();
add_syms!(sut, &base, {
meta <- meta1: IdentKind::Meta,
@ -912,28 +917,31 @@ mod test {
}
#[test]
fn graph_sort_missing_node() -> AsgResult<(), u8> {
fn graph_sort_missing_node() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "sym");
let dep = symbol_dummy!(2, "dep");
let sym_node = sut.declare(
&sym,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let sym_node = sut
.declare(
&sym,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
sut.set_fragment(sym_node, FragmentText::from("foo"))?;
sut.set_fragment(sym_node, FragmentText::from("foo"))
.unwrap();
let (_, _) = sut.add_dep_lookup(&sym, &dep);
match sut.sort(&vec![sym_node]) {
Ok(_) => panic!("Unexpected success - dependency is not in graph"),
Err(AsgError::UnexpectedNode(_)) => (),
Err(SortableAsgError::MissingObjectKind(_)) => (),
_ => {
panic!("Incorrect error result when dependency is not in graph")
}
@ -943,7 +951,7 @@ mod test {
}
#[test]
fn graph_sort_no_roots() -> AsgResult<(), u8> {
fn graph_sort_no_roots() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "sym");
@ -959,32 +967,38 @@ mod test {
}
#[test]
fn graph_sort_simple_cycle() -> AsgResult<(), u8> {
fn graph_sort_simple_cycle() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym = Symbol::new_dummy(SymbolIndex::from_u32(2), "sym");
let dep = Symbol::new_dummy(SymbolIndex::from_u32(3), "dep");
let sym_node = sut.declare(
&sym,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let sym_node = sut
.declare(
&sym,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
let dep_node = sut.declare(
&dep,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let dep_node = sut
.declare(
&dep,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
sut.set_fragment(sym_node, FragmentText::from("foo"))?;
sut.set_fragment(dep_node, FragmentText::from("bar"))?;
sut.set_fragment(sym_node, FragmentText::from("foo"))
.unwrap();
sut.set_fragment(dep_node, FragmentText::from("bar"))
.unwrap();
let (_, _) = sut.add_dep_lookup(&sym, &dep);
let (_, _) = sut.add_dep_lookup(&dep, &sym);
@ -995,7 +1009,7 @@ mod test {
vec![vec![dep_node.into(), sym_node.into()]];
match result {
Ok(_) => panic!("sort did not detect cycle"),
Err(AsgError::Cycles(scc)) => assert_eq!(expected, scc),
Err(SortableAsgError::Cycles(scc)) => assert_eq!(expected, scc),
Err(e) => panic!("unexpected error: {}", e),
}
@ -1003,7 +1017,7 @@ mod test {
}
#[test]
fn graph_sort_two_simple_cycles() -> AsgResult<(), u8> {
fn graph_sort_two_simple_cycles() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym = Symbol::new_dummy(SymbolIndex::from_u32(2), "sym");
@ -1011,46 +1025,58 @@ mod test {
let dep = Symbol::new_dummy(SymbolIndex::from_u32(4), "dep");
let dep2 = Symbol::new_dummy(SymbolIndex::from_u32(5), "dep2");
let sym_node = sut.declare(
&sym,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let sym_node = sut
.declare(
&sym,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
let sym2_node = sut.declare(
&sym2,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let sym2_node = sut
.declare(
&sym2,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
let dep_node = sut.declare(
&dep,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let dep_node = sut
.declare(
&dep,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
let dep2_node = sut.declare(
&dep2,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let dep2_node = sut
.declare(
&dep2,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
sut.set_fragment(sym_node, FragmentText::from("foo"))?;
sut.set_fragment(sym2_node, FragmentText::from("bar"))?;
sut.set_fragment(dep_node, FragmentText::from("baz"))?;
sut.set_fragment(dep2_node, FragmentText::from("huh"))?;
sut.set_fragment(sym_node, FragmentText::from("foo"))
.unwrap();
sut.set_fragment(sym2_node, FragmentText::from("bar"))
.unwrap();
sut.set_fragment(dep_node, FragmentText::from("baz"))
.unwrap();
sut.set_fragment(dep2_node, FragmentText::from("huh"))
.unwrap();
let (_, _) = sut.add_dep_lookup(&sym, &dep);
let (_, _) = sut.add_dep_lookup(&dep, &sym);
@ -1065,7 +1091,7 @@ mod test {
];
match result {
Ok(_) => panic!("sort did not detect cycle"),
Err(AsgError::Cycles(scc)) => assert_eq!(expected, scc),
Err(SortableAsgError::Cycles(scc)) => assert_eq!(expected, scc),
Err(e) => panic!("unexpected error: {}", e),
}
@ -1073,32 +1099,39 @@ mod test {
}
#[test]
fn graph_sort_no_cycle_with_edge_to_same_node() -> AsgResult<(), u8> {
fn graph_sort_no_cycle_with_edge_to_same_node() -> SortableAsgResult<(), u8>
{
let mut sut = Sut::new();
let sym = Symbol::new_dummy(SymbolIndex::from_u32(2), "sym");
let dep = Symbol::new_dummy(SymbolIndex::from_u32(3), "dep");
let sym_node = sut.declare(
&sym,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let sym_node = sut
.declare(
&sym,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
let dep_node = sut.declare(
&dep,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let dep_node = sut
.declare(
&dep,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
sut.set_fragment(sym_node, FragmentText::from("foo"))?;
sut.set_fragment(dep_node, FragmentText::from("bar"))?;
sut.set_fragment(sym_node, FragmentText::from("foo"))
.unwrap();
sut.set_fragment(dep_node, FragmentText::from("bar"))
.unwrap();
let (_, _) = sut.add_dep_lookup(&sym, &dep);
let (_, _) = sut.add_dep_lookup(&sym, &dep);
@ -1114,43 +1147,52 @@ mod test {
}
#[test]
fn graph_sort_cycle_with_a_few_steps() -> AsgResult<(), u8> {
fn graph_sort_cycle_with_a_few_steps() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym1 = Symbol::new_dummy(SymbolIndex::from_u32(1), "sym1");
let sym2 = Symbol::new_dummy(SymbolIndex::from_u32(2), "sym2");
let sym3 = Symbol::new_dummy(SymbolIndex::from_u32(3), "sym3");
let sym1_node = sut.declare(
&sym1,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let sym1_node = sut
.declare(
&sym1,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
let sym2_node = sut.declare(
&sym2,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let sym2_node = sut
.declare(
&sym2,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
let sym3_node = sut.declare(
&sym3,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let sym3_node = sut
.declare(
&sym3,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
sut.set_fragment(sym1_node, FragmentText::from("foo"))?;
sut.set_fragment(sym2_node, FragmentText::from("bar"))?;
sut.set_fragment(sym3_node, FragmentText::from("baz"))?;
sut.set_fragment(sym1_node, FragmentText::from("foo"))
.unwrap();
sut.set_fragment(sym2_node, FragmentText::from("bar"))
.unwrap();
sut.set_fragment(sym3_node, FragmentText::from("baz"))
.unwrap();
let (_, _) = sut.add_dep_lookup(&sym1, &sym2);
let (_, _) = sut.add_dep_lookup(&sym2, &sym3);
@ -1162,7 +1204,7 @@ mod test {
vec![vec![sym3_node.into(), sym2_node.into(), sym1_node.into()]];
match result {
Ok(_) => panic!("sort did not detect cycle"),
Err(AsgError::Cycles(scc)) => assert_eq!(expected, scc),
Err(SortableAsgError::Cycles(scc)) => assert_eq!(expected, scc),
Err(e) => panic!("unexpected error: {}", e),
}
@ -1171,43 +1213,52 @@ mod test {
#[test]
fn graph_sort_cyclic_function_with_non_function_with_a_few_steps(
) -> AsgResult<(), u8> {
) -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym1 = Symbol::new_dummy(SymbolIndex::from_u32(1), "sym1");
let sym2 = Symbol::new_dummy(SymbolIndex::from_u32(2), "sym2");
let sym3 = Symbol::new_dummy(SymbolIndex::from_u32(3), "sym3");
let sym1_node = sut.declare(
&sym1,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let sym1_node = sut
.declare(
&sym1,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
let sym2_node = sut.declare(
&sym2,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let sym2_node = sut
.declare(
&sym2,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
let sym3_node = sut.declare(
&sym3,
IdentKind::Func(Dim::default(), SymDtype::Empty),
Source {
virtual_: true,
..Default::default()
},
)?;
let sym3_node = sut
.declare(
&sym3,
IdentKind::Func(Dim::default(), SymDtype::Empty),
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
sut.set_fragment(sym1_node, FragmentText::from("foo"))?;
sut.set_fragment(sym2_node, FragmentText::from("bar"))?;
sut.set_fragment(sym3_node, FragmentText::from("baz"))?;
sut.set_fragment(sym1_node, FragmentText::from("foo"))
.unwrap();
sut.set_fragment(sym2_node, FragmentText::from("bar"))
.unwrap();
sut.set_fragment(sym3_node, FragmentText::from("baz"))
.unwrap();
let (_, _) = sut.add_dep_lookup(&sym1, &sym2);
let (_, _) = sut.add_dep_lookup(&sym2, &sym3);
@ -1219,7 +1270,7 @@ mod test {
vec![vec![sym3_node.into(), sym2_node.into(), sym1_node.into()]];
match result {
Ok(_) => panic!("sort did not detect cycle"),
Err(AsgError::Cycles(scc)) => assert_eq!(expected, scc),
Err(SortableAsgError::Cycles(scc)) => assert_eq!(expected, scc),
Err(e) => panic!("unexpected error: {}", e),
}
@ -1227,43 +1278,52 @@ mod test {
}
#[test]
fn graph_sort_cyclic_bookended_by_functions() -> AsgResult<(), u8> {
fn graph_sort_cyclic_bookended_by_functions() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym1 = Symbol::new_dummy(SymbolIndex::from_u32(1), "sym1");
let sym2 = Symbol::new_dummy(SymbolIndex::from_u32(2), "sym2");
let sym3 = Symbol::new_dummy(SymbolIndex::from_u32(3), "sym3");
let sym1_node = sut.declare(
&sym1,
IdentKind::Func(Dim::default(), SymDtype::Empty),
Source {
virtual_: true,
..Default::default()
},
)?;
let sym1_node = sut
.declare(
&sym1,
IdentKind::Func(Dim::default(), SymDtype::Empty),
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
let sym2_node = sut.declare(
&sym2,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let sym2_node = sut
.declare(
&sym2,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
let sym3_node = sut.declare(
&sym3,
IdentKind::Func(Dim::default(), SymDtype::Empty),
Source {
virtual_: true,
..Default::default()
},
)?;
let sym3_node = sut
.declare(
&sym3,
IdentKind::Func(Dim::default(), SymDtype::Empty),
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
sut.set_fragment(sym1_node, FragmentText::from("foo"))?;
sut.set_fragment(sym2_node, FragmentText::from("bar"))?;
sut.set_fragment(sym3_node, FragmentText::from("baz"))?;
sut.set_fragment(sym1_node, FragmentText::from("foo"))
.unwrap();
sut.set_fragment(sym2_node, FragmentText::from("bar"))
.unwrap();
sut.set_fragment(sym3_node, FragmentText::from("baz"))
.unwrap();
let (_, _) = sut.add_dep_lookup(&sym1, &sym2);
let (_, _) = sut.add_dep_lookup(&sym2, &sym3);
@ -1275,7 +1335,7 @@ mod test {
vec![vec![sym3_node.into(), sym2_node.into(), sym1_node.into()]];
match result {
Ok(_) => panic!("sort did not detect cycle"),
Err(AsgError::Cycles(scc)) => assert_eq!(expected, scc),
Err(SortableAsgError::Cycles(scc)) => assert_eq!(expected, scc),
Err(e) => panic!("unexpected error: {}", e),
}
@ -1283,32 +1343,38 @@ mod test {
}
#[test]
fn graph_sort_cyclic_function_ignored() -> AsgResult<(), u8> {
fn graph_sort_cyclic_function_ignored() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym = Symbol::new_dummy(SymbolIndex::from_u32(2), "sym");
let dep = Symbol::new_dummy(SymbolIndex::from_u32(3), "dep");
let sym_node = sut.declare(
&sym,
IdentKind::Func(Dim::default(), SymDtype::Empty),
Source {
virtual_: true,
..Default::default()
},
)?;
let sym_node = sut
.declare(
&sym,
IdentKind::Func(Dim::default(), SymDtype::Empty),
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
let dep_node = sut.declare(
&dep,
IdentKind::Func(Dim::default(), SymDtype::Empty),
Source {
virtual_: true,
..Default::default()
},
)?;
let dep_node = sut
.declare(
&dep,
IdentKind::Func(Dim::default(), SymDtype::Empty),
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
sut.set_fragment(sym_node, FragmentText::from("foo"))?;
sut.set_fragment(dep_node, FragmentText::from("bar"))?;
sut.set_fragment(sym_node, FragmentText::from("foo"))
.unwrap();
sut.set_fragment(dep_node, FragmentText::from("bar"))
.unwrap();
let (_, _) = sut.add_dep_lookup(&sym, &dep);
let (_, _) = sut.add_dep_lookup(&dep, &sym);
@ -1324,43 +1390,52 @@ mod test {
}
#[test]
fn graph_sort_cyclic_function_is_bookended() -> AsgResult<(), u8> {
fn graph_sort_cyclic_function_is_bookended() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym1 = Symbol::new_dummy(SymbolIndex::from_u32(1), "sym1");
let sym2 = Symbol::new_dummy(SymbolIndex::from_u32(2), "sym2");
let sym3 = Symbol::new_dummy(SymbolIndex::from_u32(3), "sym3");
let sym1_node = sut.declare(
&sym1,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let sym1_node = sut
.declare(
&sym1,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
let sym2_node = sut.declare(
&sym2,
IdentKind::Func(Dim::default(), SymDtype::Empty),
Source {
virtual_: true,
..Default::default()
},
)?;
let sym2_node = sut
.declare(
&sym2,
IdentKind::Func(Dim::default(), SymDtype::Empty),
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
let sym3_node = sut.declare(
&sym3,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let sym3_node = sut
.declare(
&sym3,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
sut.set_fragment(sym1_node, FragmentText::from("foo"))?;
sut.set_fragment(sym2_node, FragmentText::from("bar"))?;
sut.set_fragment(sym3_node, FragmentText::from("baz"))?;
sut.set_fragment(sym1_node, FragmentText::from("foo"))
.unwrap();
sut.set_fragment(sym2_node, FragmentText::from("bar"))
.unwrap();
sut.set_fragment(sym3_node, FragmentText::from("baz"))
.unwrap();
let (_, _) = sut.add_dep_lookup(&sym1, &sym2);
let (_, _) = sut.add_dep_lookup(&sym2, &sym3);
@ -1372,7 +1447,7 @@ mod test {
vec![vec![sym3_node.into(), sym2_node.into(), sym1_node.into()]];
match result {
Ok(_) => panic!("sort did not detect cycle"),
Err(AsgError::Cycles(scc)) => assert_eq!(expected, scc),
Err(SortableAsgError::Cycles(scc)) => assert_eq!(expected, scc),
Err(e) => panic!("unexpected error: {}", e),
}
@ -1380,43 +1455,52 @@ mod test {
}
#[test]
fn graph_sort_ignore_non_linked() -> AsgResult<(), u8> {
fn graph_sort_ignore_non_linked() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym = Symbol::new_dummy(SymbolIndex::from_u32(2), "sym");
let dep = Symbol::new_dummy(SymbolIndex::from_u32(3), "dep");
let ignored = Symbol::new_dummy(SymbolIndex::from_u32(4), "ignored");
let sym_node = sut.declare(
&sym,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let sym_node = sut
.declare(
&sym,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
let dep_node = sut.declare(
&dep,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let dep_node = sut
.declare(
&dep,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
let ignored_node = sut.declare(
&ignored,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)?;
let ignored_node = sut
.declare(
&ignored,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
sut.set_fragment(sym_node, FragmentText::from("foo"))?;
sut.set_fragment(dep_node, FragmentText::from("bar"))?;
sut.set_fragment(ignored_node, FragmentText::from("baz"))?;
sut.set_fragment(sym_node, FragmentText::from("foo"))
.unwrap();
sut.set_fragment(dep_node, FragmentText::from("bar"))
.unwrap();
sut.set_fragment(ignored_node, FragmentText::from("baz"))
.unwrap();
let (_, _) = sut.add_dep_lookup(&sym, &dep);
let (_, _) = sut.add_dep_lookup(&ignored, &sym);

View File

@ -86,7 +86,7 @@ where
name: &'i Symbol<'i>,
kind: IdentKind,
src: Source<'i>,
) -> AsgResult<ObjectRef<Ix>, Ix>;
) -> AsgResult<ObjectRef<Ix>>;
/// Declare an abstract identifier.
///
@ -113,7 +113,7 @@ where
name: &'i Symbol<'i>,
kind: IdentKind,
src: Source<'i>,
) -> AsgResult<ObjectRef<Ix>, Ix>;
) -> AsgResult<ObjectRef<Ix>>;
/// Set the fragment associated with a concrete identifier.
///
@ -124,7 +124,7 @@ where
&mut self,
identi: ObjectRef<Ix>,
text: FragmentText,
) -> AsgResult<ObjectRef<Ix>, Ix>;
) -> AsgResult<ObjectRef<Ix>>;
/// Retrieve an object from the graph by [`ObjectRef`].
///
@ -189,14 +189,20 @@ where
fn sort(
&'i self,
roots: &[ObjectRef<Ix>],
) -> AsgResult<Sections<'i, O>, Ix>;
) -> SortableAsgResult<Sections<'i, O>, Ix>;
}
/// A [`Result`] with a hard-coded [`AsgError`] error type.
///
/// This is the result of every [`Asg`] operation that could potentially
/// fail in error.
pub type AsgResult<T, Ix> = Result<T, AsgError<Ix>>;
pub type AsgResult<T> = Result<T, AsgError>;
/// A [`Result`] with a hard-coded [`SortableAsgError`] error type.
///
/// This is the result of every [`SortableAsg`] operation that could
/// potentially fail in error.
pub type SortableAsgResult<T, Ix> = Result<T, SortableAsgError<Ix>>;
/// Reference to an [object][super::object] stored within the [`Asg`].
///
@ -240,7 +246,7 @@ pub type Node<O> = Option<O>;
/// so this stores only owned values.
/// The caller will know the problem values.
#[derive(Debug, PartialEq)]
pub enum AsgError<Ix: IndexType> {
pub enum AsgError {
/// An object could not change state in the manner requested.
///
/// See [`Asg::declare`] and [`Asg::set_fragment`] for more
@ -250,24 +256,20 @@ pub enum AsgError<Ix: IndexType> {
/// The node was not expected in the current context
UnexpectedNode(String),
/// The graph has a cyclic dependency
Cycles(Vec<Vec<ObjectRef<Ix>>>),
}
impl<Ix: IndexType> std::fmt::Display for AsgError<Ix> {
impl std::fmt::Display for AsgError {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::ObjectTransition(err) => std::fmt::Display::fmt(&err, fmt),
Self::UnexpectedNode(msg) => {
write!(fmt, "unexpected node: {}", msg)
}
Self::Cycles(_) => write!(fmt, "cyclic dependencies"),
}
}
}
impl<Ix: IndexType> std::error::Error for AsgError<Ix> {
impl std::error::Error for AsgError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::ObjectTransition(err) => err.source(),
@ -276,12 +278,52 @@ impl<Ix: IndexType> std::error::Error for AsgError<Ix> {
}
}
impl<Ix: IndexType> From<TransitionError> for AsgError<Ix> {
impl From<TransitionError> for AsgError {
fn from(err: TransitionError) -> Self {
Self::ObjectTransition(err)
}
}
/// Error during graph sorting.
///
/// These errors reflect barriers to meaningfully understanding the
/// properties of the data in the graph with respect to sorting.
/// It does not represent bad underlying data that does not affect the
/// sorting process.
#[derive(Debug, PartialEq)]
pub enum SortableAsgError<Ix: IndexType> {
/// The kind of an object encountered during sorting could not be
/// determined.
///
/// Sorting uses the object kind to place objects into their appropriate
/// sections.
/// It should never be the case that a resolved object has no kind,
/// so this likely represents a compiler bug.
MissingObjectKind(String),
/// The graph has a cyclic dependency.
Cycles(Vec<Vec<ObjectRef<Ix>>>),
}
impl<Ix: IndexType> std::fmt::Display for SortableAsgError<Ix> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::MissingObjectKind(name) => write!(
fmt,
"internal error: missing object kind for object `{}` (this may be a compiler bug!)",
name,
),
Self::Cycles(_) => write!(fmt, "cyclic dependencies"),
}
}
}
impl<Ix: IndexType> std::error::Error for SortableAsgError<Ix> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
#[cfg(test)]
mod test {
use super::*;

View File

@ -196,7 +196,10 @@ mod ident;
mod object;
mod section;
pub use graph::{Asg, AsgError, AsgResult, IndexType, ObjectRef, SortableAsg};
pub use graph::{
Asg, AsgError, AsgResult, IndexType, ObjectRef, SortableAsg,
SortableAsgError,
};
pub use ident::{DataType, Dim, IdentKind, IdentKindError};
pub use object::{
FragmentText, IdentObject, IdentObjectData, IdentObjectState, Source,

View File

@ -25,8 +25,8 @@ use crate::fs::{
};
use crate::global;
use crate::ir::asg::{
Asg, AsgError, DefaultAsg, IdentObject, IdentObjectData, Sections,
SortableAsg,
Asg, DefaultAsg, IdentObject, IdentObjectData, Sections, SortableAsg,
SortableAsgError,
};
use crate::obj::xmle::writer::XmleWriter;
use crate::obj::xmlo::{AsgBuilder, AsgBuilderState, XmloReader};
@ -72,7 +72,7 @@ pub fn xmle(package_path: &str, output: &str) -> Result<(), Box<dyn Error>> {
let mut sorted = match depgraph.sort(&roots) {
Ok(sections) => sections,
Err(AsgError::Cycles(cycles)) => {
Err(SortableAsgError::Cycles(cycles)) => {
let msg: Vec<String> = cycles
.into_iter()
.map(|cycle| {

View File

@ -81,7 +81,7 @@ use std::fmt::Display;
use std::hash::BuildHasher;
pub type Result<'i, S, Ix> =
std::result::Result<AsgBuilderState<'i, S, Ix>, AsgBuilderError<Ix>>;
std::result::Result<AsgBuilderState<'i, S, Ix>, AsgBuilderError>;
/// Builder state between imports.
///
@ -289,7 +289,7 @@ where
/// Error populating graph with [`XmloResult`]-derived data.
#[derive(Debug, PartialEq)]
pub enum AsgBuilderError<Ix: IndexType> {
pub enum AsgBuilderError {
/// Error with the source `xmlo` file.
XmloError(XmloError),
@ -297,7 +297,7 @@ pub enum AsgBuilderError<Ix: IndexType> {
IdentKindError(IdentKindError),
/// [`Asg`] operation error.
AsgError(AsgError<Ix>),
AsgError(AsgError),
/// Fragment encountered for an unknown identifier.
MissingFragmentIdent(String),
@ -309,7 +309,7 @@ pub enum AsgBuilderError<Ix: IndexType> {
BadEligRef(String),
}
impl<Ix: IndexType> Display for AsgBuilderError<Ix> {
impl Display for AsgBuilderError {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::XmloError(e) => e.fmt(fmt),
@ -331,25 +331,25 @@ impl<Ix: IndexType> Display for AsgBuilderError<Ix> {
}
}
impl<Ix: IndexType> From<XmloError> for AsgBuilderError<Ix> {
impl From<XmloError> for AsgBuilderError {
fn from(src: XmloError) -> Self {
Self::XmloError(src)
}
}
impl<Ix: IndexType> From<IdentKindError> for AsgBuilderError<Ix> {
impl From<IdentKindError> for AsgBuilderError {
fn from(src: IdentKindError) -> Self {
Self::IdentKindError(src)
}
}
impl<Ix: IndexType> From<AsgError<Ix>> for AsgBuilderError<Ix> {
fn from(src: AsgError<Ix>) -> Self {
impl From<AsgError> for AsgBuilderError {
fn from(src: AsgError) -> Self {
Self::AsgError(src)
}
}
impl<Ix: IndexType> Error for AsgBuilderError<Ix> {
impl Error for AsgBuilderError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::XmloError(e) => Some(e),