tamer: asg::graph: Index Root->Pkg with canonical names
The previous commit introduced canonical names, and this uses them to index. The next step will be to utilize those names to look up packages on definition rather than creating a new package node, so that references to yet-to-be-defined (or yet-to-be-imported) packages can be resolved on the graph. DEV-13162main
parent
92c9c9ba2f
commit
7cfe6a6f8d
|
@ -442,13 +442,75 @@ fn pkg_canonical_name() {
|
|||
|
||||
let asg = sut.finalize().unwrap().into_context();
|
||||
|
||||
let pkg = asg
|
||||
.root(S1)
|
||||
let oi_root = asg.root(S1);
|
||||
let oi_pkg = oi_root
|
||||
.edges_filtered::<Pkg>(&asg)
|
||||
.next()
|
||||
.expect("cannot find package from root");
|
||||
|
||||
assert_eq!(Some(name), pkg.resolve(&asg).canonical_name());
|
||||
assert_eq!(Some(name), oi_pkg.resolve(&asg).canonical_name());
|
||||
|
||||
// We should be able to find the same package by its index.
|
||||
let oi_pkg_indexed = asg.lookup(oi_root, name);
|
||||
assert_eq!(
|
||||
Some(oi_pkg),
|
||||
oi_pkg_indexed,
|
||||
"package was not indexed at Root"
|
||||
);
|
||||
}
|
||||
|
||||
// This isn't supposed to happen in practice,
|
||||
// especially with normal usage of TAME where names are generated from
|
||||
// filenames.
|
||||
#[test]
|
||||
fn pkg_cannot_redeclare() {
|
||||
let name = SPair("foo/bar".into(), S2);
|
||||
let name2 = SPair("foo/bar".into(), S5);
|
||||
let namefix = SPair("foo/fix".into(), S6);
|
||||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
BindIdent(name),
|
||||
PkgEnd(S3),
|
||||
|
||||
PkgStart(S4),
|
||||
// Attempt to define a package of the same name.
|
||||
BindIdent(name2),
|
||||
|
||||
// RECOVERY: Use a proper name.
|
||||
BindIdent(namefix),
|
||||
PkgEnd(S7),
|
||||
];
|
||||
|
||||
let mut sut = Sut::parse(toks.into_iter());
|
||||
|
||||
assert_eq!(
|
||||
#[rustfmt::skip]
|
||||
vec![
|
||||
Ok(Incomplete), // PkgStart
|
||||
Ok(Incomplete), // BindIdent
|
||||
Ok(Incomplete), // PkgEnd
|
||||
|
||||
Ok(Incomplete), // PkgStart
|
||||
Err(ParseError::StateError(
|
||||
AsgError::PkgRedeclare(name, name2)
|
||||
)),
|
||||
// RECOVERY: Ignore the attempted name
|
||||
Ok(Incomplete), // BindIdent
|
||||
Ok(Incomplete), // PkgEnd
|
||||
],
|
||||
sut.by_ref().collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
let asg = sut.finalize().unwrap().into_context();
|
||||
|
||||
// The second package should be available under the recovery name.
|
||||
let oi_root = asg.root(S1);
|
||||
let oi_pkg = asg
|
||||
.lookup::<Pkg>(oi_root, namefix)
|
||||
.expect("failed to locate package by its recovery name");
|
||||
assert_eq!(S4.merge(S7).unwrap(), oi_pkg.resolve(&asg).span());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -463,9 +525,11 @@ fn pkg_cannot_rename() {
|
|||
// Attempt to provide a name a second time.
|
||||
BindIdent(name2),
|
||||
// RECOVERY: Just ignore it.
|
||||
PkgEnd(S3),
|
||||
PkgEnd(S4),
|
||||
];
|
||||
|
||||
let mut sut = Sut::parse(toks.into_iter());
|
||||
|
||||
assert_eq!(
|
||||
vec![
|
||||
Ok(Incomplete), // PkgStart
|
||||
|
@ -474,8 +538,17 @@ fn pkg_cannot_rename() {
|
|||
// RECOVERY: Ignore the attempted rename
|
||||
Ok(Incomplete), // PkgEnd
|
||||
],
|
||||
Sut::parse(toks.into_iter()).collect::<Vec<_>>(),
|
||||
sut.by_ref().collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
let asg = sut.finalize().unwrap().into_context();
|
||||
|
||||
// The original name should have been kept.
|
||||
let oi_root = asg.root(S1);
|
||||
let oi_pkg = asg
|
||||
.lookup::<Pkg>(oi_root, name)
|
||||
.expect("failed to locate package by its original name");
|
||||
assert_eq!(S1.merge(S4).unwrap(), oi_pkg.resolve(&asg).span());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -61,6 +61,12 @@ pub enum AsgError {
|
|||
/// whereas _declaring_ an identifier provides metadata about it.
|
||||
IdentRedefine(SPair, Span),
|
||||
|
||||
/// A package of this same name has already been defined.
|
||||
///
|
||||
/// The [`SPair`]s represent the original and redefinition names
|
||||
/// respectively.
|
||||
PkgRedeclare(SPair, SPair),
|
||||
|
||||
/// Attempted to rename a package from the first [`SPair`] to the
|
||||
/// second.
|
||||
///
|
||||
|
@ -155,6 +161,11 @@ impl Display for AsgError {
|
|||
IdentRedefine(spair, _) => {
|
||||
write!(f, "cannot redefine {}", TtQuote::wrap(spair))
|
||||
}
|
||||
PkgRedeclare(orig, _) => write!(
|
||||
f,
|
||||
"attempted to redeclare or redefine package {}",
|
||||
TtQuote::wrap(orig),
|
||||
),
|
||||
PkgRename(from, to) => write!(
|
||||
f,
|
||||
"attempted to rename package {} to {}",
|
||||
|
@ -236,6 +247,11 @@ impl Diagnostic for AsgError {
|
|||
.help(" defined and its definition cannot be changed."),
|
||||
],
|
||||
|
||||
PkgRedeclare(orig, redef) => vec![
|
||||
orig.note("package originally declared here"),
|
||||
redef.error("attempting to redeclare or redefine package here"),
|
||||
],
|
||||
|
||||
PkgRename(from, to) => vec![
|
||||
from.note("package was originally named here"),
|
||||
to.error("attempted to rename package here"),
|
||||
|
|
|
@ -190,6 +190,27 @@ impl Asg {
|
|||
self.graph.node_count()
|
||||
}
|
||||
|
||||
pub(super) fn try_index<
|
||||
O: ObjectRelatable,
|
||||
OS: ObjectIndexRelTo<O>,
|
||||
S: Into<SymbolId>,
|
||||
>(
|
||||
&mut self,
|
||||
imm_env: OS,
|
||||
name: S,
|
||||
oi: ObjectIndex<O>,
|
||||
) -> Result<(), ObjectIndex<O>> {
|
||||
let sym = name.into();
|
||||
let prev = self
|
||||
.index
|
||||
.insert((O::rel_ty(), sym, imm_env.widen()), oi.widen());
|
||||
|
||||
match prev {
|
||||
None => Ok(()),
|
||||
Some(oi) => Err(oi.must_narrow_into::<O>()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Index the provided symbol `name` as representing the
|
||||
/// [`ObjectIndex`] in the immediate environment `imm_env`.
|
||||
///
|
||||
|
@ -216,14 +237,12 @@ impl Asg {
|
|||
oi: ObjectIndex<O>,
|
||||
) {
|
||||
let sym = name.into();
|
||||
let prev = self
|
||||
.index
|
||||
.insert((O::rel_ty(), sym, imm_env.widen()), oi.widen());
|
||||
let prev = self.try_index(imm_env, sym, oi);
|
||||
|
||||
// We should never overwrite indexes
|
||||
#[allow(unused_variables)] // used only for debug
|
||||
#[allow(unused_imports)]
|
||||
if let Some(prev_oi) = prev {
|
||||
if let Err(prev_oi) = prev {
|
||||
use crate::fmt::{DisplayWrapper, TtQuote};
|
||||
crate::debug_diagnostic_panic!(
|
||||
vec![
|
||||
|
|
|
@ -202,12 +202,25 @@ impl ObjectIndex<Pkg> {
|
|||
|
||||
/// Attempt to assign a canonical name to this package.
|
||||
///
|
||||
/// This assignment will fail if the package already has a name.
|
||||
/// This assignment will fail if the package either already has a name
|
||||
/// or if a package of the same name has already been declared.
|
||||
pub fn assign_canonical_name(
|
||||
self,
|
||||
asg: &mut Asg,
|
||||
name: SPair,
|
||||
) -> Result<Self, AsgError> {
|
||||
let oi_root = asg.root(name);
|
||||
|
||||
asg.try_index(oi_root, name, self).map_err(|oi_prev| {
|
||||
let prev = oi_prev.resolve(asg);
|
||||
|
||||
// unwrap note: a canonical name must exist for this error to
|
||||
// have been thrown,
|
||||
// but this will at least not blow up if something really
|
||||
// odd happens.
|
||||
AsgError::PkgRedeclare(prev.canonical_name().unwrap_or(name), name)
|
||||
})?;
|
||||
|
||||
self.try_map_obj(asg, |pkg| pkg.assign_canonical_name(name))
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue