netidx_bscript/typ/
tvar.rs

1use crate::{
2    expr::ModPath,
3    typ::{FnType, PrintFlag, Type, PRINT_FLAGS},
4};
5use arcstr::ArcStr;
6use compact_str::format_compact;
7use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
8use std::{
9    cmp::{Eq, PartialEq},
10    fmt::{self, Debug},
11    hash::Hash,
12    ops::Deref,
13};
14use triomphe::Arc;
15
16atomic_id!(TVarId);
17
18pub(super) fn would_cycle_inner(addr: usize, t: &Type) -> bool {
19    match t {
20        Type::Primitive(_) | Type::Bottom | Type::Ref { .. } => false,
21        Type::TVar(t) => {
22            Arc::as_ptr(&t.read().typ).addr() == addr
23                || match &*t.read().typ.read() {
24                    None => false,
25                    Some(t) => would_cycle_inner(addr, t),
26                }
27        }
28        Type::Array(a) => would_cycle_inner(addr, &**a),
29        Type::ByRef(t) => would_cycle_inner(addr, t),
30        Type::Tuple(ts) => ts.iter().any(|t| would_cycle_inner(addr, t)),
31        Type::Variant(_, ts) => ts.iter().any(|t| would_cycle_inner(addr, t)),
32        Type::Struct(ts) => ts.iter().any(|(_, t)| would_cycle_inner(addr, t)),
33        Type::Set(s) => s.iter().any(|t| would_cycle_inner(addr, t)),
34        Type::Fn(f) => {
35            let FnType { args, vargs, rtype, constraints } = &**f;
36            args.iter().any(|t| would_cycle_inner(addr, &t.typ))
37                || match vargs {
38                    None => false,
39                    Some(t) => would_cycle_inner(addr, t),
40                }
41                || would_cycle_inner(addr, &rtype)
42                || constraints.read().iter().any(|a| {
43                    Arc::as_ptr(&a.0.read().typ).addr() == addr
44                        || would_cycle_inner(addr, &a.1)
45                })
46        }
47    }
48}
49
50#[derive(Debug)]
51pub struct TVarInnerInner {
52    pub(super) id: TVarId,
53    pub(super) typ: Arc<RwLock<Option<Type>>>,
54}
55
56#[derive(Debug)]
57pub struct TVarInner {
58    pub name: ArcStr,
59    pub(super) typ: RwLock<TVarInnerInner>,
60}
61
62#[derive(Debug, Clone)]
63pub struct TVar(Arc<TVarInner>);
64
65impl fmt::Display for TVar {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        if !PRINT_FLAGS.get().contains(PrintFlag::DerefTVars) {
68            write!(f, "'{}", self.name)
69        } else {
70            write!(f, "'{}: ", self.name)?;
71            match &*self.read().typ.read() {
72                Some(t) => write!(f, "{t}"),
73                None => write!(f, "unbound"),
74            }
75        }
76    }
77}
78
79impl Default for TVar {
80    fn default() -> Self {
81        Self::empty_named(ArcStr::from(format_compact!("_{}", TVarId::new().0).as_str()))
82    }
83}
84
85impl Deref for TVar {
86    type Target = TVarInner;
87
88    fn deref(&self) -> &Self::Target {
89        &*self.0
90    }
91}
92
93impl PartialEq for TVar {
94    fn eq(&self, other: &Self) -> bool {
95        let t0 = self.read();
96        let t1 = other.read();
97        t0.typ.as_ptr().addr() == t1.typ.as_ptr().addr() || {
98            let t0 = t0.typ.read();
99            let t1 = t1.typ.read();
100            *t0 == *t1
101        }
102    }
103}
104
105impl Eq for TVar {}
106
107impl PartialOrd for TVar {
108    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
109        let t0 = self.read();
110        let t1 = other.read();
111        if t0.typ.as_ptr().addr() == t1.typ.as_ptr().addr() {
112            Some(std::cmp::Ordering::Equal)
113        } else {
114            let t0 = t0.typ.read();
115            let t1 = t1.typ.read();
116            t0.partial_cmp(&*t1)
117        }
118    }
119}
120
121impl Ord for TVar {
122    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
123        let t0 = self.read();
124        let t1 = other.read();
125        if t0.typ.as_ptr().addr() == t1.typ.as_ptr().addr() {
126            std::cmp::Ordering::Equal
127        } else {
128            let t0 = t0.typ.read();
129            let t1 = t1.typ.read();
130            t0.cmp(&*t1)
131        }
132    }
133}
134
135impl TVar {
136    pub fn scope_refs(&self, scope: &ModPath) -> Self {
137        match Type::TVar(self.clone()).scope_refs(scope) {
138            Type::TVar(tv) => tv,
139            _ => unreachable!(),
140        }
141    }
142
143    pub fn empty_named(name: ArcStr) -> Self {
144        Self(Arc::new(TVarInner {
145            name,
146            typ: RwLock::new(TVarInnerInner {
147                id: TVarId::new(),
148                typ: Arc::new(RwLock::new(None)),
149            }),
150        }))
151    }
152
153    pub fn named(name: ArcStr, typ: Type) -> Self {
154        Self(Arc::new(TVarInner {
155            name,
156            typ: RwLock::new(TVarInnerInner {
157                id: TVarId::new(),
158                typ: Arc::new(RwLock::new(Some(typ))),
159            }),
160        }))
161    }
162
163    pub fn read(&self) -> RwLockReadGuard<TVarInnerInner> {
164        self.typ.read()
165    }
166
167    pub fn write(&self) -> RwLockWriteGuard<TVarInnerInner> {
168        self.typ.write()
169    }
170
171    /// make self an alias for other
172    pub fn alias(&self, other: &Self) {
173        let mut s = self.write();
174        let o = other.read();
175        s.id = o.id;
176        s.typ = Arc::clone(&o.typ);
177    }
178
179    /// copy self from other
180    pub fn copy(&self, other: &Self) {
181        let s = self.read();
182        let o = other.read();
183        *s.typ.write() = o.typ.read().clone();
184    }
185
186    pub fn normalize(&self) -> Self {
187        match &mut *self.read().typ.write() {
188            None => (),
189            Some(t) => {
190                *t = t.normalize();
191            }
192        }
193        self.clone()
194    }
195
196    pub fn unbind(&self) {
197        *self.read().typ.write() = None
198    }
199
200    pub(super) fn would_cycle(&self, t: &Type) -> bool {
201        let addr = Arc::as_ptr(&self.read().typ).addr();
202        would_cycle_inner(addr, t)
203    }
204}