tamer: ld::xmle::lower::test: Use AIR (decouple from Asg and index)

This uses AIR---the ASG's proper public interface now---to construct the
graph for tests, just as all the other modern tests do.  This is change
works towards encapsulating index operations (both creation and lookups) so
that the index can be moved off of Asg and into AIR, where it belongs.  More
information on that and rationale to come.

DEV-13162
main
Mike Gerwitz 2023-05-17 10:48:01 -04:00
parent b238366bee
commit 79fa10f26b
2 changed files with 109 additions and 121 deletions

View File

@ -19,31 +19,24 @@
use super::*; use super::*;
use crate::{ use crate::{
asg::{AsgError, FragmentText, Ident, IdentKind, ObjectIndex, Source}, asg::{
air::{Air, AirAggregate},
AsgError, FragmentText, Ident, IdentKind, Source,
},
ld::xmle::{section::PushResult, Sections}, ld::xmle::{section::PushResult, Sections},
parse::util::SPair, parse::{util::SPair, ParseState},
span::dummy::*, span::dummy::*,
sym::SymbolId, sym::SymbolId,
}; };
use std::fmt::Debug;
fn declare( use Air::*;
asg: &mut Asg,
name: SPair,
kind: IdentKind,
src: Source,
) -> Result<ObjectIndex<Ident>, AsgError> {
let oi_root = asg.root(name);
oi_root.declare(asg, name, kind, src)
}
fn lookup_or_missing(asg: &mut Asg, name: SPair) -> ObjectIndex<Ident> { fn asg_from_toks(toks: impl IntoIterator<Item = Air, IntoIter: Debug>) -> Asg {
let oi_root = asg.root(name); let mut sut = AirAggregate::parse(toks.into_iter());
oi_root.lookup_or_missing(asg, name) assert!(sut.all(|x| x.is_ok()));
}
/// Create a graph with the expected {ret,}map head/tail identifiers. sut.finalize().unwrap().into_context()
fn make_asg() -> Asg {
Asg::new()
} }
#[test] #[test]
@ -85,48 +78,57 @@ fn graph_sort() -> SortResult<()> {
} }
} }
let mut asg = make_asg(); let name_a_dep = SPair("adep".into(), S4);
let name_a = SPair("a".into(), S3);
let name_a_dep_dep = SPair("adepdep".into(), S2);
// Add them in an unsorted order. #[rustfmt::skip]
let adep = declare( let toks = [
&mut asg, PkgStart(S1, SPair("/pkg".into(), S1)),
SPair("adep".into(), S1), // Intentionally out-of-order.
IdentKind::Meta, IdentDecl(
Default::default(), name_a_dep,
) IdentKind::Meta,
.unwrap(); Default::default(),
let a = declare( ),
&mut asg,
SPair("a".into(), S2),
IdentKind::Meta,
Default::default(),
)
.unwrap();
let adepdep = declare(
&mut asg,
SPair("adepdep".into(), S3),
IdentKind::Meta,
Default::default(),
)
.unwrap();
a.add_opaque_dep(&mut asg, adep); IdentDecl(
adep.add_opaque_dep(&mut asg, adepdep); name_a,
IdentKind::Meta,
Default::default(),
),
a.root(&mut asg); IdentDecl(
name_a_dep_dep,
IdentKind::Meta,
Default::default(),
),
IdentDep(name_a, name_a_dep),
IdentDep(name_a_dep, name_a_dep_dep),
IdentRoot(name_a),
PkgEnd(S5),
];
let asg = asg_from_toks(toks);
let sections = sort(&asg, StubSections { pushed: Vec::new() })?; let sections = sort(&asg, StubSections { pushed: Vec::new() })?;
let expected = vec![
// Post-order
name_a_dep_dep,
name_a_dep,
name_a,
]
.into_iter()
.collect::<Vec<_>>();
assert_eq!( assert_eq!(
sections.pushed, expected,
vec![ sections
// Post-order .pushed
asg.get(adepdep).unwrap(), .iter()
asg.get(adep).unwrap(), .map(|ident| ident.name())
asg.get(a).unwrap(), .collect::<Vec<_>>(),
]
.into_iter()
.collect::<Vec<_>>()
); );
Ok(()) Ok(())
@ -134,27 +136,30 @@ fn graph_sort() -> SortResult<()> {
#[test] #[test]
fn graph_sort_missing_node() -> SortResult<()> { fn graph_sort_missing_node() -> SortResult<()> {
let mut asg = make_asg();
let sym = SPair("sym".into(), S1); let sym = SPair("sym".into(), S1);
let dep = SPair("dep".into(), S2); let dep = SPair("dep".into(), S2);
let oi_dep = lookup_or_missing(&mut asg, dep); #[rustfmt::skip]
let toks = [
PkgStart(S1, SPair("/pkg".into(), S1)),
IdentDecl(
sym,
IdentKind::Tpl,
Source {
virtual_: true,
..Default::default()
},
),
IdentFragment(sym, FragmentText::from("foo")),
declare( // dep will be added as Missing
&mut asg, IdentDep(sym, dep),
sym,
IdentKind::Tpl, IdentRoot(sym),
Source { PkgEnd(S5),
virtual_: true, ];
..Default::default()
}, let asg = asg_from_toks(toks);
)
.unwrap()
.set_fragment(&mut asg, FragmentText::from("foo"))
.unwrap()
.add_opaque_dep(&mut asg, oi_dep)
.root(&mut asg);
match sort(&asg, Sections::new()) { match sort(&asg, Sections::new()) {
Ok(_) => panic!("Unexpected success - dependency is not in graph"), Ok(_) => panic!("Unexpected success - dependency is not in graph"),
@ -170,66 +175,43 @@ fn graph_sort_missing_node() -> SortResult<()> {
Ok(()) Ok(())
} }
#[test]
fn graph_sort_no_roots_same_as_empty_graph() -> SortResult<()> {
let mut asg = make_asg();
// "empty" (it has the head/tail {ret,}map objects)
let asg_empty = make_asg();
let sym = SPair("sym".into(), S1);
let dep = SPair("dep".into(), S2);
let oi_sym = lookup_or_missing(&mut asg, sym);
let oi_dep = lookup_or_missing(&mut asg, dep);
oi_sym.add_opaque_dep(&mut asg, oi_dep);
assert_eq!(
sort(&asg, Sections::new()),
sort(&asg_empty, Sections::new())
);
Ok(())
}
#[test] #[test]
fn graph_sort_simple_cycle() -> SortResult<()> { fn graph_sort_simple_cycle() -> SortResult<()> {
let mut asg = make_asg();
let sym = SPair("sym".into(), S1); let sym = SPair("sym".into(), S1);
let dep = SPair("dep".into(), S2); let dep = SPair("dep".into(), S2);
let oi_sym = declare( #[rustfmt::skip]
&mut asg, let toks = [
sym, PkgStart(S1, SPair("/pkg".into(), S1)),
IdentKind::Tpl, IdentDecl(
Source { sym,
virtual_: true, IdentKind::Tpl,
..Default::default() Source {
}, virtual_: true,
) ..Default::default()
.unwrap() },
.set_fragment(&mut asg, FragmentText::from("foo")) ),
.unwrap(); IdentFragment(sym, FragmentText::from("foo")),
let oi_dep = declare( IdentDecl(
&mut asg, dep,
dep, IdentKind::Tpl,
IdentKind::Tpl, Source {
Source { virtual_: true,
virtual_: true, ..Default::default()
..Default::default() },
}, ),
) IdentFragment(dep, FragmentText::from("bar")),
.unwrap()
.set_fragment(&mut asg, FragmentText::from("bar"))
.unwrap();
oi_sym.add_opaque_dep(&mut asg, oi_dep); // Produce a cycle (which will be an error)
oi_dep.add_opaque_dep(&mut asg, oi_sym); IdentDep(sym, dep),
IdentDep(dep, sym),
oi_sym.root(&mut asg); IdentRoot(sym),
PkgEnd(S5),
];
let asg = asg_from_toks(toks);
let result = sort(&asg, Sections::new()); let result = sort(&asg, Sections::new());
match result { match result {

View File

@ -87,6 +87,12 @@
// Added for use with `rustfmt::skip`, // Added for use with `rustfmt::skip`,
// so that we can ignore formatting more precisely. // so that we can ignore formatting more precisely.
#![feature(stmt_expr_attributes)] #![feature(stmt_expr_attributes)]
// Allows using `impl Trait` for associated type bounds instead of having to
// extract it into a more verbose `where` clause.
// This is not necessary,
// and may not even be desirable,
// but it's a nice option to have if `impl` would otherwise be used.
#![feature(associated_type_bounds)]
// We build docs for private items. // We build docs for private items.
#![allow(rustdoc::private_intra_doc_links)] #![allow(rustdoc::private_intra_doc_links)]
// For sym::prefill recursive macro `static_symbols!`. // For sym::prefill recursive macro `static_symbols!`.