netidx_bscript/typ/
tvar.rs1use 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 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 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}