Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
path: root/tamer
diff options
context:
space:
mode:
authorMike Gerwitz <mike.gerwitz@ryansg.com>2020-03-25 15:37:55 -0400
committerMike Gerwitz <mike.gerwitz@ryansg.com>2020-03-26 09:14:26 -0400
commitd6762ab54736091c12c924ae3ba94d70763ee6d1 (patch)
tree8ad8cc2c84025fcd990f50e5e592f8872ff7923d /tamer
parent8de174d6a22af73c31d5ba88857ced391eb0f183 (diff)
downloadtame-d6762ab54736091c12c924ae3ba94d70763ee6d1.tar.gz
tame-d6762ab54736091c12c924ae3ba94d70763ee6d1.tar.bz2
tame-d6762ab54736091c12c924ae3ba94d70763ee6d1.zip
[DEV-7087] TAMER: Type compatability check during extern resolution
This properly verifies extern types, and cleans up Asg's API a little so that externs aren't handled much differently than other declarations. With that said, after making src optional, I realized that we will indeed want source information for externs themselves so we can direct the user to what package is expecting that symbol (as the old linker does). So this approach will not work, and I'll have to undo some of those changes.
Diffstat (limited to 'tamer')
-rw-r--r--tamer/src/ir/asg/base.rs208
-rw-r--r--tamer/src/ir/asg/graph.rs37
-rw-r--r--tamer/src/ir/asg/mod.rs4
-rw-r--r--tamer/src/ir/asg/object.rs255
-rw-r--r--tamer/src/ld/poc.rs22
5 files changed, 304 insertions, 222 deletions
diff --git a/tamer/src/ir/asg/base.rs b/tamer/src/ir/asg/base.rs
index 431172b..91a00b5 100644
--- a/tamer/src/ir/asg/base.rs
+++ b/tamer/src/ir/asg/base.rs
@@ -199,7 +199,7 @@ where
&mut self,
name: &'i Symbol<'i>,
kind: IdentKind,
- src: Source<'i>,
+ src: Option<Source<'i>>,
) -> AsgResult<ObjectRef<Ix>, Ix> {
if let Some(existing) = self.lookup(name) {
let node = self.graph.node_weight_mut(existing.0).unwrap();
@@ -229,19 +229,6 @@ where
Ok(ObjectRef(node))
}
- fn declare_extern(
- &mut self,
- name: &'i Symbol<'i>,
- expected_kind: IdentKind,
- ) -> AsgResult<ObjectRef<Ix>, Ix> {
- // TODO: resolution!
- let node = self.graph.add_node(Some(O::extern_(name, expected_kind)));
-
- self.index_identifier(name, node);
-
- Ok(ObjectRef(node))
- }
-
fn set_fragment(
&mut self,
identi: ObjectRef<Ix>,
@@ -412,9 +399,8 @@ mod test {
#[derive(Debug, Default, PartialEq)]
struct StubIdentObject<'i> {
given_missing: Option<&'i Symbol<'i>>,
- given_ident: Option<(&'i Symbol<'i>, IdentKind, Source<'i>)>,
- given_extern: Option<(&'i Symbol<'i>, IdentKind)>,
- given_redeclare: Option<(IdentKind, Source<'i>)>,
+ given_ident: Option<(&'i Symbol<'i>, IdentKind, Option<Source<'i>>)>,
+ given_redeclare: Option<(IdentKind, Option<Source<'i>>)>,
given_set_fragment: Option<FragmentText>,
fail_redeclare: RefCell<Option<TransitionError>>,
}
@@ -423,14 +409,12 @@ mod test {
fn name(&self) -> Option<&'i Symbol<'i>> {
self.given_missing
.or(self.given_ident.as_ref().map(|args| args.0))
- .or(self.given_extern.as_ref().map(|args| args.0))
}
fn kind(&self) -> Option<&IdentKind> {
self.given_ident
.as_ref()
.map(|args| &args.1)
- .or(self.given_extern.as_ref().map(|args| &args.1))
.or(self.given_redeclare.as_ref().map(|args| &args.0))
}
@@ -458,7 +442,7 @@ mod test {
fn ident(
name: &'i Symbol<'i>,
kind: IdentKind,
- src: Source<'i>,
+ src: Option<Source<'i>>,
) -> Self {
Self {
given_ident: Some((name, kind, src)),
@@ -466,17 +450,10 @@ mod test {
}
}
- fn extern_(name: &'i Symbol<'i>, kind: IdentKind) -> Self {
- Self {
- given_extern: Some((name, kind)),
- ..Default::default()
- }
- }
-
fn redeclare(
mut self,
kind: IdentKind,
- src: Source<'i>,
+ src: Option<Source<'i>>,
) -> TransitionResult<StubIdentObject<'i>> {
if self.fail_redeclare.borrow().is_some() {
let err = self.fail_redeclare.replace(None).unwrap();
@@ -528,19 +505,19 @@ mod test {
let nodea = sut.declare(
&syma,
IdentKind::Meta,
- Source {
+ Some(Source {
desc: Some("a".to_string()),
..Default::default()
- },
+ }),
)?;
let nodeb = sut.declare(
&symb,
IdentKind::Worksheet,
- Source {
+ Some(Source {
desc: Some("b".to_string()),
..Default::default()
- },
+ }),
)?;
assert_ne!(nodea, nodeb);
@@ -549,10 +526,10 @@ mod test {
Some((
&syma,
IdentKind::Meta,
- Source {
+ Some(Source {
desc: Some("a".to_string()),
..Default::default()
- },
+ }),
)),
sut.get(nodea).unwrap().given_ident
);
@@ -561,10 +538,10 @@ mod test {
Some((
&symb,
IdentKind::Worksheet,
- Source {
+ Some(Source {
desc: Some("b".to_string()),
..Default::default()
- },
+ }),
)),
sut.get(nodeb).unwrap().given_ident
);
@@ -580,10 +557,10 @@ mod test {
let node = sut.declare(
&sym,
IdentKind::Meta,
- Source {
+ Some(Source {
generated: true,
..Default::default()
- },
+ }),
)?;
assert_eq!(Some(node), sut.lookup(&sym));
@@ -592,27 +569,12 @@ mod test {
}
#[test]
- fn declare_extern() -> AsgResult<(), u8> {
- let mut sut = Sut::with_capacity(0, 0);
-
- let sym = symbol_dummy!(1, "extern");
- let node = sut.declare_extern(&sym, IdentKind::Meta)?;
-
- assert_eq!(
- Some((&sym, IdentKind::Meta)),
- sut.get(node).unwrap().given_extern,
- );
-
- Ok(())
- }
-
- #[test]
fn declare_returns_existing() -> AsgResult<(), u8> {
let mut sut = Sut::with_capacity(0, 0);
let sym = symbol_dummy!(1, "symdup");
let src = Source::default();
- let node = sut.declare(&sym, IdentKind::Meta, src.clone())?;
+ let node = sut.declare(&sym, IdentKind::Meta, Some(src.clone()))?;
// Remember that our stub does not care about compatibility.
let rekind = IdentKind::Class(Dim::from_u8(3));
@@ -620,14 +582,15 @@ mod test {
desc: Some("redeclare".into()),
..Default::default()
};
- let redeclare = sut.declare(&sym, rekind.clone(), resrc.clone())?;
+ let redeclare =
+ sut.declare(&sym, rekind.clone(), Some(resrc.clone()))?;
// We don't care what the objects are for this test, just that the
// same node is referenced.
assert_eq!(node, redeclare);
assert_eq!(
- Some((rekind, resrc)),
+ Some((rekind, Some(resrc))),
sut.get(node).unwrap().given_redeclare,
);
@@ -646,18 +609,19 @@ mod test {
};
// Set up an object to fail redeclaration.
- let node = sut.declare(&sym, IdentKind::Meta, src.clone())?;
+ let node = sut.declare(&sym, IdentKind::Meta, Some(src.clone()))?;
let obj = sut.get(node).unwrap();
let terr = TransitionError::Incompatible(String::from("test fail"));
obj.fail_redeclare.replace(Some(terr.clone()));
// Should invoke StubIdentObject::redeclare on the above `obj`.
- let result = sut.declare(&sym, IdentKind::Meta, Source::default());
+ let result =
+ sut.declare(&sym, IdentKind::Meta, Some(Source::default()));
if let Err(err) = result {
// The node should have been restored.
let obj = sut.get(node).unwrap();
- assert_eq!(src, obj.given_ident.as_ref().unwrap().2);
+ assert_eq!(Some(src), obj.given_ident.as_ref().unwrap().2);
assert_eq!(AsgError::ObjectTransition(terr), err);
@@ -676,7 +640,7 @@ mod test {
generated: true,
..Default::default()
};
- let node = sut.declare(&sym, IdentKind::Meta, src.clone())?;
+ let node = sut.declare(&sym, IdentKind::Meta, Some(src.clone()))?;
let fragment = "a fragment".to_string();
let node_with_frag = sut.set_fragment(node, fragment.clone())?;
@@ -690,7 +654,7 @@ mod test {
let obj = sut.get(node).unwrap();
- assert_eq!(Some((&sym, IdentKind::Meta, src,)), obj.given_ident);
+ assert_eq!(Some((&sym, IdentKind::Meta, Some(src))), obj.given_ident);
assert_eq!(Some(fragment), obj.given_set_fragment);
Ok(())
@@ -705,8 +669,10 @@ mod test {
let sym = symbol_dummy!(1, "sym");
let dep = symbol_dummy!(2, "dep");
- let symnode = sut.declare(&sym, IdentKind::Meta, Source::default())?;
- let depnode = sut.declare(&dep, IdentKind::Meta, Source::default())?;
+ let symnode =
+ sut.declare(&sym, IdentKind::Meta, Some(Source::default()))?;
+ let depnode =
+ sut.declare(&dep, IdentKind::Meta, Some(Source::default()))?;
sut.add_dep(symnode, depnode);
assert!(sut.has_dep(symnode, depnode));
@@ -726,8 +692,8 @@ mod test {
let sym = symbol_dummy!(1, "sym");
let dep = symbol_dummy!(2, "dep");
- let _ = sut.declare(&sym, IdentKind::Meta, Source::default())?;
- let _ = sut.declare(&dep, IdentKind::Meta, Source::default())?;
+ let _ = sut.declare(&sym, IdentKind::Meta, Some(Source::default()))?;
+ let _ = sut.declare(&dep, IdentKind::Meta, Some(Source::default()))?;
let (symnode, depnode) = sut.add_dep_lookup(&sym, &dep);
assert!(sut.has_dep(symnode, depnode));
@@ -768,14 +734,14 @@ mod test {
};
// Check with a declared value
- let declared = sut.declare(&sym, IdentKind::Meta, src.clone())?;
+ let declared = sut.declare(&sym, IdentKind::Meta, Some(src.clone()))?;
assert_eq!(symnode, declared);
let obj = sut.get(declared).unwrap();
assert_eq!(Some(&sym), obj.given_missing);
- assert_eq!(Some((IdentKind::Meta, src)), obj.given_redeclare);
+ assert_eq!(Some((IdentKind::Meta, Some(src))), obj.given_redeclare);
Ok(())
}
@@ -801,7 +767,7 @@ mod test {
let sym = symbol_dummy!(i, stringify!($name));
- $sut.declare(&sym, $kind, Source::default())?;
+ $sut.declare(&sym, $kind, Some(Source::default()))?;
let (_, _) = $sut.add_dep_lookup($base, &sym);
$dest.push(sym);
@@ -820,7 +786,7 @@ mod test {
let base = symbol_dummy!(1, "sym1");
let base_node =
- sut.declare(&base, IdentKind::Map, Source::default())?;
+ sut.declare(&base, IdentKind::Map, Some(Source::default()))?;
add_syms!(sut, &base, {
meta <- meta1: IdentKind::Meta,
@@ -863,10 +829,10 @@ mod test {
let sym_node = sut.declare(
&sym,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
sut.set_fragment(sym_node, FragmentText::from("foo"))?;
@@ -910,19 +876,19 @@ mod test {
let sym_node = sut.declare(
&sym,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
let dep_node = sut.declare(
&dep,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
sut.set_fragment(sym_node, FragmentText::from("foo"))?;
@@ -956,37 +922,37 @@ mod test {
let sym_node = sut.declare(
&sym,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
let sym2_node = sut.declare(
&sym2,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
let dep_node = sut.declare(
&dep,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
let dep2_node = sut.declare(
&dep2,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
sut.set_fragment(sym_node, FragmentText::from("foo"))?;
@@ -1024,19 +990,19 @@ mod test {
let sym_node = sut.declare(
&sym,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
let dep_node = sut.declare(
&dep,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
sut.set_fragment(sym_node, FragmentText::from("foo"))?;
@@ -1066,28 +1032,28 @@ mod test {
let sym1_node = sut.declare(
&sym1,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
let sym2_node = sut.declare(
&sym2,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
let sym3_node = sut.declare(
&sym3,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
sut.set_fragment(sym1_node, FragmentText::from("foo"))?;
@@ -1123,28 +1089,28 @@ mod test {
let sym1_node = sut.declare(
&sym1,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
let sym2_node = sut.declare(
&sym2,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
let sym3_node = sut.declare(
&sym3,
IdentKind::Func(Dim::default(), SymDtype::Empty),
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
sut.set_fragment(sym1_node, FragmentText::from("foo"))?;
@@ -1179,28 +1145,28 @@ mod test {
let sym1_node = sut.declare(
&sym1,
IdentKind::Func(Dim::default(), SymDtype::Empty),
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
let sym2_node = sut.declare(
&sym2,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
let sym3_node = sut.declare(
&sym3,
IdentKind::Func(Dim::default(), SymDtype::Empty),
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
sut.set_fragment(sym1_node, FragmentText::from("foo"))?;
@@ -1234,19 +1200,19 @@ mod test {
let sym_node = sut.declare(
&sym,
IdentKind::Func(Dim::default(), SymDtype::Empty),
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
let dep_node = sut.declare(
&dep,
IdentKind::Func(Dim::default(), SymDtype::Empty),
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
sut.set_fragment(sym_node, FragmentText::from("foo"))?;
@@ -1276,28 +1242,28 @@ mod test {
let sym1_node = sut.declare(
&sym1,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
let sym2_node = sut.declare(
&sym2,
IdentKind::Func(Dim::default(), SymDtype::Empty),
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
let sym3_node = sut.declare(
&sym3,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
sut.set_fragment(sym1_node, FragmentText::from("foo"))?;
@@ -1332,28 +1298,28 @@ mod test {
let sym_node = sut.declare(
&sym,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
let dep_node = sut.declare(
&dep,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
let ignored_node = sut.declare(
&ignored,
IdentKind::Tpl,
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
)?;
sut.set_fragment(sym_node, FragmentText::from("foo"))?;
diff --git a/tamer/src/ir/asg/graph.rs b/tamer/src/ir/asg/graph.rs
index 52d83cc..3d16491 100644
--- a/tamer/src/ir/asg/graph.rs
+++ b/tamer/src/ir/asg/graph.rs
@@ -62,45 +62,36 @@ where
/// then the operation will fail;
/// otherwise,
/// the existing identifier will be returned.
- /// For more information on state transitions that can occur when
- /// redeclaring an identifier that already exists,
- /// see [`IdentObjectState::redeclare`].
///
- /// A successful declaration will add an identifier to the graph
- /// and return an [`ObjectRef`] reference.
- fn declare(
- &mut self,
- name: &'i Symbol<'i>,
- kind: IdentKind,
- src: Source<'i>,
- ) -> AsgResult<ObjectRef<Ix>, Ix>;
-
- /// Declare an abstract identifier.
- ///
- /// An _extern_ declaration declares an identifier the same as
- /// [`Asg::declare`],
- /// but omits source information.
+ /// If `src` is omitted,
+ /// then an abstract identifier (an _extern_) is declared.
/// Externs are identifiers that are expected to be defined somewhere
/// else ("externally"),
/// and are resolved at [link-time][crate::ld].
///
/// If a concrete identifier has already been declared (see
/// [`Asg::declare`]),
- /// then the declarations will be compared and,
+ /// then extern declarations will be compared and,
/// if compatible,
/// the identifier will be immediately _resolved_ and the object
/// on the graph will not be altered.
/// Resolution will otherwise fail in error.
///
- /// See [`IdentObjectState::extern_`] and
- /// [`IdentObjectState::redeclare`] for more information on
- /// compatibility related to extern resolution.
- fn declare_extern(
+ /// For more information on state transitions that can occur when
+ /// redeclaring an identifier that already exists,
+ /// see [`IdentObjectState::redeclare`].
+ ///
+ /// A successful declaration will add an identifier to the graph
+ /// and return an [`ObjectRef`] reference.
+ fn declare(
&mut self,
name: &'i Symbol<'i>,
- expected_kind: IdentKind,
+ kind: IdentKind,
+ src: Option<Source<'i>>,
) -> AsgResult<ObjectRef<Ix>, Ix>;
+ /// Declare an abstract identifier.
+
/// Set the fragment associated with a concrete identifier.
///
/// Fragments are intended for use by the [linker][crate::ld].
diff --git a/tamer/src/ir/asg/mod.rs b/tamer/src/ir/asg/mod.rs
index 2d9bd4d..17986ec 100644
--- a/tamer/src/ir/asg/mod.rs
+++ b/tamer/src/ir/asg/mod.rs
@@ -133,7 +133,7 @@
//!
//! // Once declared, the missing identifier changes state and dependencies
//! // are retained.
-//! asg.declare(identa_sym, IdentKind::Meta, Source::default())?;
+//! asg.declare(identa_sym, IdentKind::Meta, Some(Source::default()))?;
//!
//! assert_eq!(
//! Some(&IdentObject::Ident(identa_sym, IdentKind::Meta, Source::default())),
@@ -168,7 +168,7 @@
//! #
//! // Fragments can be attached to resolved identifiers.
//! let ident = asg.declare(
-//! interner.intern("ident"), IdentKind::Meta, Source::default()
+//! interner.intern("ident"), IdentKind::Meta, Some(Source::default())
//! )?;
//! asg.set_fragment(ident, FragmentText::from("test fragment"))?;
//!
diff --git a/tamer/src/ir/asg/object.rs b/tamer/src/ir/asg/object.rs
index a9d90a9..ef54713 100644
--- a/tamer/src/ir/asg/object.rs
+++ b/tamer/src/ir/asg/object.rs
@@ -189,18 +189,22 @@ where
fn missing(ident: &'i Symbol<'i>) -> T;
/// Produce an object representing a concrete identifier.
- fn ident(name: &'i Symbol<'i>, kind: IdentKind, src: Source<'i>) -> T;
-
- /// Produce an object representing an extern.
- fn extern_(name: &'i Symbol<'i>, kind: IdentKind) -> T;
+ fn ident(
+ name: &'i Symbol<'i>,
+ kind: IdentKind,
+ src: Option<Source<'i>>,
+ ) -> T;
/// Attempt to redeclare an identifier with additional information.
///
/// For specific information on compatibility rules,
/// see implementers of this trait,
/// since rules may vary between implementations.
- fn redeclare(self, kind: IdentKind, src: Source<'i>)
- -> TransitionResult<T>;
+ fn redeclare(
+ self,
+ kind: IdentKind,
+ src: Option<Source<'i>>,
+ ) -> TransitionResult<T>;
/// Attach a code fragment (compiled text) to an identifier.
///
@@ -218,12 +222,15 @@ impl<'i> IdentObjectState<'i, IdentObject<'i>> for IdentObject<'i> {
IdentObject::Missing(ident)
}
- fn ident(name: &'i Symbol<'i>, kind: IdentKind, src: Source<'i>) -> Self {
- IdentObject::Ident(name, kind, src)
- }
-
- fn extern_(name: &'i Symbol<'i>, kind: IdentKind) -> Self {
- IdentObject::Extern(name, kind)
+ fn ident(
+ name: &'i Symbol<'i>,
+ kind: IdentKind,
+ src: Option<Source<'i>>,
+ ) -> Self {
+ match src {
+ Some(s) => IdentObject::Ident(name, kind, s),
+ None => IdentObject::Extern(name, kind),
+ }
}
/// Attempt to redeclare an identifier with additional information.
@@ -247,44 +254,63 @@ impl<'i> IdentObjectState<'i, IdentObject<'i>> for IdentObject<'i> {
fn redeclare(
mut self,
kind: IdentKind,
- src: Source<'i>,
+ src: Option<Source<'i>>,
) -> TransitionResult<IdentObject<'i>> {
- match self {
- IdentObject::Ident(_, _, ref mut orig_src)
- if orig_src.virtual_ && src.override_ =>
- {
- *orig_src = src;
- Ok(self)
- }
-
- IdentObject::Extern(name, ref orig_kind) => {
- if orig_kind != &kind {
- let err = TransitionError::ExternResolution {
- name: name.to_string(),
- expected: orig_kind.clone(),
- given: kind.clone(),
- };
+ match src {
+ None => match self.kind() {
+ None => Ok(IdentObject::Extern(self.name().unwrap(), kind)),
+ Some(cur_kind) => {
+ if cur_kind != &kind {
+ let err = TransitionError::ExternResolution {
+ name: self.name().unwrap().to_string(),
+ expected: kind.clone(),
+ given: cur_kind.clone(),
+ };
+
+ return Err((self, err));
+ }
- return Err((self, err));
+ // Resolved successfully, so keep what we already have.
+ Ok(self)
+ }
+ },
+ Some(new_src) => match self {
+ IdentObject::Ident(_, _, ref mut orig_src)
+ if orig_src.virtual_ && new_src.override_ =>
+ {
+ *orig_src = new_src;
+ Ok(self)
}
- Ok(IdentObject::Ident(name, kind, src))
- }
+ IdentObject::Extern(name, ref orig_kind) => {
+ if orig_kind != &kind {
+ let err = TransitionError::ExternResolution {
+ name: name.to_string(),
+ expected: orig_kind.clone(),
+ given: kind.clone(),
+ };
- // TODO: no override-override
- IdentObject::IdentFragment(name, _, orig_src, _)
- if orig_src.virtual_ && src.override_ =>
- {
- // clears fragment, which is no longer applicable
- Ok(IdentObject::Ident(name, kind, src))
- }
+ return Err((self, err));
+ }
- IdentObject::Missing(name) | IdentObject::Ident(name, _, _) => {
- Ok(IdentObject::Ident(name, kind, src))
- }
+ Ok(IdentObject::Ident(name, kind, new_src))
+ }
- // TODO: incompatible (check now-dangling commits)
- _ => Ok(self),
+ // TODO: no override-override
+ IdentObject::IdentFragment(name, _, orig_src, _)
+ if orig_src.virtual_ && new_src.override_ =>
+ {
+ // clears fragment, which is no longer applicable
+ Ok(IdentObject::Ident(name, kind, new_src))
+ }
+
+ IdentObject::Missing(name) | IdentObject::Ident(name, _, _) => {
+ Ok(IdentObject::Ident(name, kind, new_src))
+ }
+
+ // TODO
+ _ => Ok(self),
+ },
}
}
@@ -387,7 +413,6 @@ impl std::fmt::Display for TransitionError {
write!(fmt, "object incompatible: {}", msg)
}
- // TODO
Self::ExternResolution {
name,
expected,
@@ -673,7 +698,7 @@ mod test {
assert_eq!(
IdentObject::Ident(&sym, kind.clone(), src.clone()),
- IdentObject::ident(&sym, kind.clone(), src.clone()),
+ IdentObject::ident(&sym, kind.clone(), Some(src.clone())),
);
}
@@ -687,13 +712,31 @@ mod test {
assert_eq!(
IdentObject::Extern(&sym, kind.clone()),
- IdentObject::extern_(&sym, kind.clone()),
+ IdentObject::ident(&sym, kind.clone(), None),
);
}
+ // Extern first, then identifier
#[test]
fn redeclare_compatible_resolves() {
- let sym = symbol_dummy!(1, "extern_re");
+ let sym = symbol_dummy!(1, "extern_re_pre");
+ let kind = IdentKind::Class(Dim::from_u8(10));
+ let src = Source {
+ desc: Some("okay".into()),
+ ..Default::default()
+ };
+
+ // Compatible kind, should resolve.
+ let result = IdentObject::ident(&sym, kind.clone(), None)
+ .redeclare(kind.clone(), Some(src.clone()));
+
+ assert_eq!(Ok(IdentObject::Ident(&sym, kind, src)), result,);
+ }
+
+ // Identifier first, then extern
+ #[test]
+ fn redeclare_compatible_resolves_post() {
+ let sym = symbol_dummy!(1, "extern_re_post");
let kind = IdentKind::Class(Dim::from_u8(10));
let src = Source {
desc: Some("okay".into()),
@@ -701,26 +744,51 @@ mod test {
};
// Compatible kind, should resolve.
- let result = IdentObject::extern_(&sym, kind.clone())
- .redeclare(kind.clone(), src.clone());
+ let result =
+ IdentObject::ident(&sym, kind.clone(), Some(src.clone()))
+ .redeclare(kind.clone(), None);
assert_eq!(Ok(IdentObject::Ident(&sym, kind, src)), result,);
}
#[test]
- fn redeclare_incompatible_kind() {
- let sym = symbol_dummy!(1, "extern_re_bad");
+ fn redeclare_missing() {
+ let sym = symbol_dummy!(1, "extern_missing");
+ let kind = IdentKind::Class(Dim::from_u8(7));
+
+ let result =
+ IdentObject::missing(&sym).redeclare(kind.clone(), None);
+
+ assert_eq!(Ok(IdentObject::Extern(&sym, kind)), result);
+ }
+
+ #[test]
+ fn redeclare_another_extern() {
+ let sym = symbol_dummy!(1, "extern_extern");
+ let kind = IdentKind::Class(Dim::from_u8(20));
+
+ let result = IdentObject::ident(&sym, kind.clone(), None)
+ .redeclare(kind.clone(), None);
+
+ assert_eq!(Ok(IdentObject::Extern(&sym, kind)), result);
+ }
+
+ // Extern first, then identifier
+ #[test]
+ fn redeclare_post_incompatible_kind() {
+ let sym = symbol_dummy!(1, "extern_re_bad_post");
let kind = IdentKind::Class(Dim::from_u8(10));
let src = Source {
desc: Some("bad kind".into()),
..Default::default()
};
- let orig = IdentObject::extern_(&sym, kind.clone());
+ let orig = IdentObject::ident(&sym, kind.clone(), None);
// Incompatible kind
let kind_bad = IdentKind::Meta;
- let result = orig.clone().redeclare(kind_bad.clone(), src);
+ let result =
+ orig.clone().redeclare(kind_bad.clone(), Some(src));
match result {
Err((given_orig, err @ _)) => {
@@ -747,6 +815,52 @@ mod test {
_ => panic!("expected failure: {:?}", result),
}
}
+
+ // Identifier first, then extern
+ #[test]
+ fn redeclare_pre_incompatible_kind() {
+ let sym = symbol_dummy!(1, "extern_re_bad_pre");
+ let kind_given = IdentKind::Class(Dim::from_u8(10));
+ let src = Source {
+ desc: Some("bad kind".into()),
+ ..Default::default()
+ };
+
+ let orig = IdentObject::ident(
+ &sym,
+ kind_given.clone(),
+ Some(src.clone()),
+ );
+
+ // Extern with incompatible kind.
+ let kind_extern = IdentKind::Meta;
+ let result = orig.clone().redeclare(kind_extern.clone(), None);
+
+ match result {
+ Err((given_orig, err @ _)) => {
+ assert_eq!(orig, given_orig);
+
+ if let TransitionError::ExternResolution {
+ name: e_name,
+ expected: e_expected,
+ given: e_given,
+ } = err.clone()
+ {
+ assert_eq!(sym.to_string(), e_name);
+ assert_eq!(kind_extern, e_expected);
+ assert_eq!(kind_given, e_given);
+ }
+
+ // Formatted error
+ let msg = format!("{}", err);
+
+ assert!(msg.contains(&format!("{}", sym)));
+ assert!(msg.contains(&format!("{}", kind_extern)));
+ assert!(msg.contains(&format!("{}", kind_given)));
+ }
+ _ => panic!("expected failure: {:?}", result),
+ }
+ }
}
// TODO: incompatible
@@ -754,15 +868,18 @@ mod test {
fn redeclare_returns_existing_compatible() {
let sym = symbol_dummy!(1, "symdup");
- let first =
- IdentObject::ident(&sym, IdentKind::Meta, Source::default());
+ let first = IdentObject::ident(
+ &sym,
+ IdentKind::Meta,
+ Some(Source::default()),
+ );
// Same declaration a second time
assert_eq!(
Ok(first.clone()),
first.clone().redeclare(
first.kind().unwrap().clone(),
- first.src().unwrap().clone(),
+ Some(first.src().unwrap().clone()),
)
);
}
@@ -776,7 +893,8 @@ mod test {
};
let kind = IdentKind::Meta;
- let ident = IdentObject::ident(&sym, kind.clone(), src.clone());
+ let ident =
+ IdentObject::ident(&sym, kind.clone(), Some(src.clone()));
let text = FragmentText::from("a fragment");
let ident_with_frag = ident.set_fragment(text.clone());
@@ -789,8 +907,11 @@ mod test {
#[test]
fn add_fragment_to_fragment_fails() {
let sym = symbol_dummy!(1, "badsym");
- let ident =
- IdentObject::ident(&sym, IdentKind::Meta, Source::default());
+ let ident = IdentObject::ident(
+ &sym,
+ IdentKind::Meta,
+ Some(Source::default()),
+ );
let ident_with_frag = ident
.set_fragment("orig fragment".into())
@@ -825,10 +946,10 @@ mod test {
let virt = IdentObject::ident(
&sym,
kind.clone(),
- Source {
+ Some(Source {
virtual_: true,
..Default::default()
- },
+ }),
);
let over_src = Source {
@@ -837,7 +958,7 @@ mod test {
..Default::default()
};
- let result = virt.redeclare(kind.clone(), over_src.clone());
+ let result = virt.redeclare(kind.clone(), Some(over_src.clone()));
assert_eq!(Ok(IdentObject::Ident(&sym, kind, over_src)), result);
}
@@ -854,7 +975,8 @@ mod test {
..Default::default()
};
- let virt = IdentObject::ident(&sym, kind.clone(), virt_src.clone());
+ let virt =
+ IdentObject::ident(&sym, kind.clone(), Some(virt_src.clone()));
let text = FragmentText::from("remove me");
let virt_frag = virt.set_fragment(text.clone());
@@ -874,8 +996,9 @@ mod test {
..Default::default()
};
- let result =
- virt_frag.unwrap().redeclare(kind.clone(), over_src.clone());
+ let result = virt_frag
+ .unwrap()
+ .redeclare(kind.clone(), Some(over_src.clone()));
// The act of overriding the object should have cleared any
// existing fragment, making way for a new fragment to take its
@@ -891,7 +1014,7 @@ mod test {
..Default::default()
};
- let obj = IdentObject::ident(&sym, given, src.clone());
+ let obj = IdentObject::ident(&sym, given, Some(src.clone()));
let fragment = "a fragment".to_string();
let obj_with_frag = obj.set_fragment(fragment.clone());
diff --git a/tamer/src/ld/poc.rs b/tamer/src/ld/poc.rs
index 224fbeb..d1677da 100644
--- a/tamer/src/ld/poc.rs
+++ b/tamer/src/ld/poc.rs
@@ -174,10 +174,6 @@ fn load_xmlo<'a, 'i, I: Interner<'i>>(
Ok(XmloEvent::SymDecl(sym, attrs)) => {
if let Some(sym_src) = attrs.src {
found.insert(sym_src);
- } else if attrs.extern_ {
- // TODO: externs (they're implicitly handled, without
- // checks, by Missing)
- // depgraph.declare_extern(sym, kind);
} else {
let owned = attrs.src.is_none();
@@ -185,13 +181,19 @@ fn load_xmlo<'a, 'i, I: Interner<'i>>(
format!("sym `{}` attrs error: {}", sym, err)
});
- let mut src: Source = attrs.into();
+ let src = if attrs.extern_ {
+ None
+ } else {
+ let mut s: Source = attrs.into();
- // Existing convention is to omit @src of local package
- // (in this case, the program being linked)
- if first {
- src.pkg_name = None;
- }
+ // Existing convention is to omit @src of local package
+ // (in this case, the program being linked)
+ if first {
+ s.pkg_name = None;
+ }
+
+ Some(s)
+ };
match kind {
Ok(kindval) => {