1use crate::{env::Env, expr::ModPath, format_with_flags, PrintFlag, PRINT_FLAGS};
2use anyhow::{anyhow, bail, Result};
3use arcstr::ArcStr;
4use enumflags2::BitFlags;
5use fxhash::FxHashSet;
6use netidx::{publisher::Typ, utils::Either};
7use poolshark::local::LPooled;
8use std::{
9 cmp::{Eq, PartialEq},
10 fmt::Debug,
11 iter,
12};
13use triomphe::Arc;
14
15mod cast;
16mod contains;
17mod fntyp;
18mod matches;
19mod normalize;
20mod print;
21mod setops;
22mod tval;
23mod tvar;
24
25pub use fntyp::{FnArgType, FnType};
26pub use tval::TVal;
27pub use tvar::TVar;
28
29struct AndAc(bool);
30
31impl FromIterator<bool> for AndAc {
32 fn from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Self {
33 AndAc(iter.into_iter().all(|b| b))
34 }
35}
36
37atomic_id!(AbstractId);
38
39#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
40pub enum Type {
41 Bottom,
42 Any,
43 Primitive(BitFlags<Typ>),
44 Ref { scope: ModPath, name: ModPath, params: Arc<[Type]> },
45 Fn(Arc<FnType>),
46 Set(Arc<[Type]>),
47 TVar(TVar),
48 Error(Arc<Type>),
49 Array(Arc<Type>),
50 ByRef(Arc<Type>),
51 Tuple(Arc<[Type]>),
52 Struct(Arc<[(ArcStr, Type)]>),
53 Variant(ArcStr, Arc<[Type]>),
54 Map { key: Arc<Type>, value: Arc<Type> },
55 Abstract { id: AbstractId, params: Arc<[Type]> },
56}
57
58impl Default for Type {
59 fn default() -> Self {
60 Self::Bottom
61 }
62}
63
64impl Type {
65 pub fn empty_tvar() -> Self {
66 Type::TVar(TVar::default())
67 }
68
69 fn iter_prims(&self) -> impl Iterator<Item = Self> {
70 match self {
71 Self::Primitive(p) => {
72 Either::Left(p.iter().map(|t| Type::Primitive(t.into())))
73 }
74 t => Either::Right(iter::once(t.clone())),
75 }
76 }
77
78 pub fn is_defined(&self) -> bool {
79 match self {
80 Self::Bottom
81 | Self::Any
82 | Self::Primitive(_)
83 | Self::Fn(_)
84 | Self::Set(_)
85 | Self::Error(_)
86 | Self::Array(_)
87 | Self::ByRef(_)
88 | Self::Tuple(_)
89 | Self::Struct(_)
90 | Self::Variant(_, _)
91 | Self::Ref { .. }
92 | Self::Map { .. }
93 | Self::Abstract { .. } => true,
94 Self::TVar(tv) => tv.read().typ.read().is_some(),
95 }
96 }
97
98 pub fn lookup_ref<'a>(&'a self, env: &'a Env) -> Result<&'a Type> {
99 match self {
100 Self::Ref { scope, name, params } => {
101 let def = env
102 .lookup_typedef(scope, name)
103 .ok_or_else(|| anyhow!("undefined type {name} in {scope}"))?;
104 if def.params.len() != params.len() {
105 bail!("{} expects {} type parameters", name, def.params.len());
106 }
107 def.typ.unbind_tvars();
108 for ((tv, ct), arg) in def.params.iter().zip(params.iter()) {
109 if let Some(ct) = ct {
110 ct.check_contains(env, arg)?;
111 }
112 if !tv.would_cycle(arg) {
113 match arg {
114 Type::TVar(arg_tv) => match &*arg_tv.read().typ.read() {
115 None => *tv.read().typ.write() = Some(arg.clone()),
116 Some(t) => *tv.read().typ.write() = Some(t.clone()),
117 },
118 _ => {
119 *tv.read().typ.write() = Some(arg.clone());
120 }
121 }
122 }
123 }
124 Ok(&def.typ)
125 }
126 t => Ok(t),
127 }
128 }
129
130 pub fn any() -> Self {
131 Self::Any
132 }
133
134 pub fn boolean() -> Self {
135 Self::Primitive(Typ::Bool.into())
136 }
137
138 pub fn number() -> Self {
139 Self::Primitive(Typ::number())
140 }
141
142 pub fn int() -> Self {
143 Self::Primitive(Typ::integer())
144 }
145
146 pub fn uint() -> Self {
147 Self::Primitive(Typ::unsigned_integer())
148 }
149
150 fn strip_error_int(&self, env: &Env, hist: &mut FxHashSet<usize>) -> Option<Type> {
151 match self {
152 Type::Error(t) => match t.strip_error_int(env, hist) {
153 Some(t) => Some(t),
154 None => Some((**t).clone()),
155 },
156 Type::TVar(tv) => {
157 tv.read().typ.read().as_ref().and_then(|t| t.strip_error_int(env, hist))
158 }
159 Type::Primitive(p) => {
160 if *p == BitFlags::from(Typ::Error) {
161 Some(Type::Any)
162 } else {
163 None
164 }
165 }
166 Type::Ref { .. } => {
167 let t = self.lookup_ref(env).ok()?;
168 let addr = t as *const Type as usize;
169 if hist.insert(addr) {
170 t.strip_error_int(env, hist)
171 } else {
172 None
173 }
174 }
175 Type::Set(s) => {
176 let r = Self::flatten_set(
177 s.iter().filter_map(|t| t.strip_error_int(env, hist)),
178 );
179 match r {
180 Type::Primitive(p) if p.is_empty() => None,
181 t => Some(t),
182 }
183 }
184 Type::Array(_)
185 | Type::Map { .. }
186 | Type::ByRef(_)
187 | Type::Tuple(_)
188 | Type::Struct(_)
189 | Type::Variant(_, _)
190 | Type::Fn(_)
191 | Type::Any
192 | Type::Bottom
193 | Type::Abstract { .. } => None,
194 }
195 }
196
197 pub fn strip_error(&self, env: &Env) -> Option<Self> {
200 self.strip_error_int(env, &mut LPooled::take())
201 }
202
203 pub fn is_bot(&self) -> bool {
204 match self {
205 Type::Bottom => true,
206 Type::Any
207 | Type::Abstract { .. }
208 | Type::TVar(_)
209 | Type::Primitive(_)
210 | Type::Ref { .. }
211 | Type::Fn(_)
212 | Type::Error(_)
213 | Type::Array(_)
214 | Type::ByRef(_)
215 | Type::Tuple(_)
216 | Type::Struct(_)
217 | Type::Variant(_, _)
218 | Type::Set(_)
219 | Type::Map { .. } => false,
220 }
221 }
222
223 pub fn with_deref<R, F: FnOnce(Option<&Self>) -> R>(&self, f: F) -> R {
224 match self {
225 Self::Bottom
226 | Self::Abstract { .. }
227 | Self::Any
228 | Self::Primitive(_)
229 | Self::Fn(_)
230 | Self::Set(_)
231 | Self::Error(_)
232 | Self::Array(_)
233 | Self::ByRef(_)
234 | Self::Tuple(_)
235 | Self::Struct(_)
236 | Self::Variant(_, _)
237 | Self::Ref { .. }
238 | Self::Map { .. } => f(Some(self)),
239 Self::TVar(tv) => match tv.read().typ.read().as_ref() {
240 Some(t) => t.with_deref(f),
241 None => f(None),
242 },
243 }
244 }
245
246 pub fn scope_refs(&self, scope: &ModPath) -> Type {
247 match self {
248 Type::Bottom => Type::Bottom,
249 Type::Any => Type::Any,
250 Type::Primitive(s) => Type::Primitive(*s),
251 Type::Abstract { id, params } => Type::Abstract {
252 id: *id,
253 params: Arc::from_iter(params.iter().map(|t| t.scope_refs(scope))),
254 },
255 Type::Error(t0) => Type::Error(Arc::new(t0.scope_refs(scope))),
256 Type::Array(t0) => Type::Array(Arc::new(t0.scope_refs(scope))),
257 Type::Map { key, value } => {
258 let key = Arc::new(key.scope_refs(scope));
259 let value = Arc::new(value.scope_refs(scope));
260 Type::Map { key, value }
261 }
262 Type::ByRef(t) => Type::ByRef(Arc::new(t.scope_refs(scope))),
263 Type::Tuple(ts) => {
264 let i = ts.iter().map(|t| t.scope_refs(scope));
265 Type::Tuple(Arc::from_iter(i))
266 }
267 Type::Variant(tag, ts) => {
268 let i = ts.iter().map(|t| t.scope_refs(scope));
269 Type::Variant(tag.clone(), Arc::from_iter(i))
270 }
271 Type::Struct(ts) => {
272 let i = ts.iter().map(|(n, t)| (n.clone(), t.scope_refs(scope)));
273 Type::Struct(Arc::from_iter(i))
274 }
275 Type::TVar(tv) => match tv.read().typ.read().as_ref() {
276 None => Type::TVar(TVar::empty_named(tv.name.clone())),
277 Some(typ) => {
278 let typ = typ.scope_refs(scope);
279 Type::TVar(TVar::named(tv.name.clone(), typ))
280 }
281 },
282 Type::Ref { scope: _, name, params } => {
283 let params = Arc::from_iter(params.iter().map(|t| t.scope_refs(scope)));
284 Type::Ref { scope: scope.clone(), name: name.clone(), params }
285 }
286 Type::Set(ts) => {
287 Type::Set(Arc::from_iter(ts.iter().map(|t| t.scope_refs(scope))))
288 }
289 Type::Fn(f) => Type::Fn(Arc::new(f.scope_refs(scope))),
290 }
291 }
292}