1use crate::{
21 context::Shared,
22 types::TypeId,
23 value::{
24 Value, ValueId,
25 util::base_ref::{BaseRef, WithShared},
26 },
27};
28use jstd::Identifier;
29
30#[derive(Identifier)]
31pub struct PoisonId(usize);
32
33#[derive(Debug, Clone, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
36pub struct Poison {
37 pub type_id: TypeId,
39}
40
41pub type PoisonRef<'str, 'ctx> = BaseRef<&'ctx Shared<'str>, PoisonId>;
42
43impl<'s, 'ctx: 's, 'str: 'ctx> WithShared<'s, 'ctx, 'str> for PoisonRef<'str, 'ctx> {
44 fn shared(&'s self) -> &'ctx Shared<'str> {
45 self.ctx
46 }
47}
48
49impl<'s, 'ctx: 's, 'str: 'ctx, Ctx> BaseRef<Ctx, PoisonId>
50where
51 Self: WithShared<'s, 'ctx, 'str>,
52{
53 fn inner(&'s self) -> &'ctx Poison {
54 &self.shared().values.poisons[self.id]
55 }
56
57 pub fn type_id(&'s self) -> TypeId {
59 self.inner().type_id
60 }
61}
62
63impl std::fmt::Display for PoisonRef<'_, '_> {
64 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65 write!(f, "poison")
66 }
67}
68
69impl<'str, 'ctx> Value<'str, 'ctx> for PoisonRef<'str, 'ctx> {
70 fn id(&self) -> ValueId {
71 ValueId::Poison(self.id)
72 }
73
74 fn size(&self) -> usize {
75 self.ctx
76 .types
77 .size_of(self.ctx.values.poisons[self.id].type_id)
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use crate::testing::TestContext;
84 use crate::value::{Value, ValueId, ValueRef};
85
86 #[test]
89 fn poison_interns_and_round_trips() {
90 let tc = TestContext::new();
91 let i32_ty = tc.ctx.shared.types.get_or_make_int(4);
92 let p = tc.ctx.get_poison(i32_ty);
93 assert!(p.is_poison());
94 assert_eq!(tc.ctx.type_of(p), i32_ty);
95 assert_eq!(tc.ctx.stored_type_of(p), Some(i32_ty));
96 match ValueRef::new(p, &tc.ctx) {
97 ValueRef::Poison(r) => {
98 assert_eq!(r.type_id(), i32_ty);
99 assert_eq!(r.size(), 4);
100 }
101 _ => panic!("expected a poison ref"),
102 }
103 }
104
105 #[test]
108 fn same_type_poisons_are_distinct() {
109 let tc = TestContext::new();
110 let i64_ty = tc.ctx.shared.types.get_or_make_int(8);
111 let a = tc.ctx.get_poison(i64_ty);
112 let b = tc.ctx.get_poison(i64_ty);
113 assert_ne!(a, b, "each poison must be its own interned value");
114 assert!(matches!(a, ValueId::Poison(_)));
115 assert!(matches!(b, ValueId::Poison(_)));
116 }
117}