graphix_compiler/typ/
mod.rs

1use crate::{
2    env::Env, expr::ModPath, format_with_flags, PrintFlag, Rt, UserEvent, PRINT_FLAGS,
3};
4use anyhow::{anyhow, bail, Result};
5use arcstr::ArcStr;
6use enumflags2::BitFlags;
7use fxhash::{FxHashMap, FxHashSet};
8use netidx::{
9    publisher::{Typ, Value},
10    utils::Either,
11};
12use netidx_value::ValArray;
13use parking_lot::RwLock;
14use smallvec::{smallvec, SmallVec};
15use std::{
16    cell::RefCell,
17    cmp::{Eq, PartialEq},
18    collections::{hash_map::Entry, HashMap, HashSet},
19    fmt::{self, Debug},
20    iter,
21};
22use triomphe::Arc;
23
24mod fntyp;
25mod tval;
26mod tvar;
27
28pub use fntyp::{FnArgType, FnType};
29pub use tval::TVal;
30use tvar::would_cycle_inner;
31pub use tvar::TVar;
32
33struct AndAc(bool);
34
35impl FromIterator<bool> for AndAc {
36    fn from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Self {
37        AndAc(iter.into_iter().all(|b| b))
38    }
39}
40
41#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
42pub enum Type {
43    Bottom,
44    Any,
45    Primitive(BitFlags<Typ>),
46    Ref { scope: ModPath, name: ModPath, params: Arc<[Type]> },
47    Fn(Arc<FnType>),
48    Set(Arc<[Type]>),
49    TVar(TVar),
50    Array(Arc<Type>),
51    ByRef(Arc<Type>),
52    Tuple(Arc<[Type]>),
53    Struct(Arc<[(ArcStr, Type)]>),
54    Variant(ArcStr, Arc<[Type]>),
55}
56
57impl Default for Type {
58    fn default() -> Self {
59        Self::Bottom
60    }
61}
62
63impl Type {
64    pub fn empty_tvar() -> Self {
65        Type::TVar(TVar::default())
66    }
67
68    fn iter_prims(&self) -> impl Iterator<Item = Self> {
69        match self {
70            Self::Primitive(p) => {
71                Either::Left(p.iter().map(|t| Type::Primitive(t.into())))
72            }
73            t => Either::Right(iter::once(t.clone())),
74        }
75    }
76
77    pub fn is_defined(&self) -> bool {
78        match self {
79            Self::Bottom
80            | Self::Any
81            | Self::Primitive(_)
82            | Self::Fn(_)
83            | Self::Set(_)
84            | Self::Array(_)
85            | Self::ByRef(_)
86            | Self::Tuple(_)
87            | Self::Struct(_)
88            | Self::Variant(_, _) => true,
89            Self::TVar(tv) => tv.read().typ.read().is_some(),
90            Self::Ref { .. } => true,
91        }
92    }
93
94    pub fn lookup_ref<'a, R: Rt, E: UserEvent>(
95        &'a self,
96        env: &'a Env<R, E>,
97    ) -> Result<&'a Type> {
98        match self {
99            Self::Ref { scope, name, params } => {
100                let def = env
101                    .lookup_typedef(scope, name)
102                    .ok_or_else(|| anyhow!("undefined type {name} in {scope}"))?;
103                if def.params.len() != params.len() {
104                    bail!("{} expects {} type parameters", name, def.params.len());
105                }
106                def.typ.unbind_tvars();
107                for ((tv, ct), arg) in def.params.iter().zip(params.iter()) {
108                    if let Some(ct) = ct {
109                        ct.check_contains(env, arg)?;
110                    }
111                    if !tv.would_cycle(arg) {
112                        *tv.read().typ.write() = Some(arg.clone());
113                    }
114                }
115                Ok(&def.typ)
116            }
117            t => Ok(t),
118        }
119    }
120
121    pub fn check_contains<R: Rt, E: UserEvent>(
122        &self,
123        env: &Env<R, E>,
124        t: &Self,
125    ) -> Result<()> {
126        if self.contains(env, t)? {
127            Ok(())
128        } else {
129            format_with_flags(PrintFlag::DerefTVars | PrintFlag::ReplacePrims, || {
130                bail!("type mismatch {self} does not contain {t}")
131            })
132        }
133    }
134
135    fn contains_int<R: Rt, E: UserEvent>(
136        &self,
137        env: &Env<R, E>,
138        hist: &mut FxHashMap<(usize, usize), bool>,
139        t: &Self,
140    ) -> Result<bool> {
141        if (self as *const Type) == (t as *const Type) {
142            return Ok(true);
143        }
144        match (self, t) {
145            (
146                Self::Ref { scope: s0, name: n0, .. },
147                Self::Ref { scope: s1, name: n1, .. },
148            ) if s0 == s1 && n0 == n1 => Ok(true),
149            (t0 @ Self::Ref { .. }, t1) | (t0, t1 @ Self::Ref { .. }) => {
150                let t0 = t0.lookup_ref(env)?;
151                let t1 = t1.lookup_ref(env)?;
152                let t0_addr = (t0 as *const Type).addr();
153                let t1_addr = (t1 as *const Type).addr();
154                match hist.get(&(t0_addr, t1_addr)) {
155                    Some(r) => Ok(*r),
156                    None => {
157                        hist.insert((t0_addr, t1_addr), true);
158                        match t0.contains_int(env, hist, t1) {
159                            Ok(r) => {
160                                hist.insert((t0_addr, t1_addr), r);
161                                Ok(r)
162                            }
163                            Err(e) => {
164                                hist.remove(&(t0_addr, t1_addr));
165                                Err(e)
166                            }
167                        }
168                    }
169                }
170            }
171            (Self::TVar(t0), Self::Bottom) => {
172                if let Some(_) = &*t0.read().typ.read() {
173                    return Ok(true);
174                }
175                *t0.read().typ.write() = Some(Self::Bottom);
176                Ok(true)
177            }
178            (Self::TVar(t0), Self::Any) => {
179                if let Some(t0) = &*t0.read().typ.read() {
180                    return t0.contains_int(env, hist, t);
181                }
182                *t0.read().typ.write() = Some(Self::Any);
183                Ok(true)
184            }
185            (Self::Any, _) => Ok(true),
186            (Self::Bottom, _) | (_, Self::Bottom) => Ok(true),
187            (Self::Primitive(p0), Self::Primitive(p1)) => Ok(p0.contains(*p1)),
188            (
189                Self::Primitive(p),
190                Self::Array(_) | Self::Tuple(_) | Self::Struct(_) | Self::Variant(_, _),
191            ) => Ok(p.contains(Typ::Array)),
192            (Self::Array(t0), Self::Array(t1)) => t0.contains_int(env, hist, t1),
193            (Self::Array(t0), Self::Primitive(p)) if *p == BitFlags::from(Typ::Array) => {
194                t0.contains_int(env, hist, &Type::Primitive(BitFlags::all()))
195            }
196            (Self::Tuple(t0), Self::Tuple(t1))
197                if t0.as_ptr().addr() == t1.as_ptr().addr() =>
198            {
199                Ok(true)
200            }
201            (Self::Tuple(t0), Self::Tuple(t1)) => Ok(t0.len() == t1.len()
202                && t0
203                    .iter()
204                    .zip(t1.iter())
205                    .map(|(t0, t1)| t0.contains_int(env, hist, t1))
206                    .collect::<Result<AndAc>>()?
207                    .0),
208            (Self::Struct(t0), Self::Struct(t1))
209                if t0.as_ptr().addr() == t1.as_ptr().addr() =>
210            {
211                Ok(true)
212            }
213            (Self::Struct(t0), Self::Struct(t1)) => {
214                Ok(t0.len() == t1.len() && {
215                    // struct types are always sorted by field name
216                    t0.iter()
217                        .zip(t1.iter())
218                        .map(|((n0, t0), (n1, t1))| {
219                            Ok(n0 == n1 && t0.contains_int(env, hist, t1)?)
220                        })
221                        .collect::<Result<AndAc>>()?
222                        .0
223                })
224            }
225            (Self::Variant(tg0, t0), Self::Variant(tg1, t1))
226                if tg0.as_ptr() == tg1.as_ptr()
227                    && t0.as_ptr().addr() == t1.as_ptr().addr() =>
228            {
229                Ok(true)
230            }
231            (Self::Variant(tg0, t0), Self::Variant(tg1, t1)) => Ok(tg0 == tg1
232                && t0.len() == t1.len()
233                && t0
234                    .iter()
235                    .zip(t1.iter())
236                    .map(|(t0, t1)| t0.contains_int(env, hist, t1))
237                    .collect::<Result<AndAc>>()?
238                    .0),
239            (Self::ByRef(t0), Self::ByRef(t1)) => t0.contains_int(env, hist, t1),
240            (Self::Tuple(_), Self::Array(_))
241            | (Self::Tuple(_), Self::Primitive(_))
242            | (Self::Tuple(_), Self::Struct(_))
243            | (Self::Tuple(_), Self::Variant(_, _))
244            | (Self::Array(_), Self::Primitive(_))
245            | (Self::Array(_), Self::Tuple(_))
246            | (Self::Array(_), Self::Struct(_))
247            | (Self::Array(_), Self::Variant(_, _))
248            | (Self::Struct(_), Self::Primitive(_))
249            | (Self::Struct(_), Self::Array(_))
250            | (Self::Struct(_), Self::Tuple(_))
251            | (Self::Struct(_), Self::Variant(_, _))
252            | (Self::Variant(_, _), Self::Array(_))
253            | (Self::Variant(_, _), Self::Struct(_))
254            | (Self::Variant(_, _), Self::Primitive(_))
255            | (Self::Variant(_, _), Self::Tuple(_)) => Ok(false),
256            (Self::TVar(t0), Self::TVar(t1)) if t0.addr() == t1.addr() => Ok(true),
257            (Self::TVar(t0), tt1 @ Self::TVar(t1)) => {
258                #[derive(Debug)]
259                enum Act {
260                    RightCopy,
261                    RightAlias,
262                    LeftAlias,
263                    LeftCopy,
264                }
265                let act = {
266                    let t0 = t0.read();
267                    let t1 = t1.read();
268                    let addr = Arc::as_ptr(&t0.typ).addr();
269                    if addr == Arc::as_ptr(&t1.typ).addr() {
270                        return Ok(true);
271                    }
272                    let t0i = t0.typ.read();
273                    let t1i = t1.typ.read();
274                    match (&*t0i, &*t1i) {
275                        (Some(t0), Some(t1)) => return t0.contains_int(env, hist, &*t1),
276                        (None, None) => {
277                            if would_cycle_inner(addr, tt1) {
278                                return Ok(true);
279                            }
280                            if t0.frozen && t1.frozen {
281                                return Ok(true);
282                            }
283                            if t0.frozen {
284                                Act::RightAlias
285                            } else {
286                                Act::LeftAlias
287                            }
288                        }
289                        (Some(_), None) => {
290                            if would_cycle_inner(addr, tt1) {
291                                return Ok(true);
292                            }
293                            Act::RightCopy
294                        }
295                        (None, Some(_)) => {
296                            if would_cycle_inner(addr, tt1) {
297                                return Ok(true);
298                            }
299                            Act::LeftCopy
300                        }
301                    }
302                };
303                match act {
304                    Act::RightCopy => t1.copy(t0),
305                    Act::RightAlias => t1.alias(t0),
306                    Act::LeftAlias => t0.alias(t1),
307                    Act::LeftCopy => t0.copy(t1),
308                }
309                Ok(true)
310            }
311            (Self::TVar(t0), t1) if !t0.would_cycle(t1) => {
312                if let Some(t0) = &*t0.read().typ.read() {
313                    return t0.contains_int(env, hist, t1);
314                }
315                *t0.read().typ.write() = Some(t1.clone());
316                Ok(true)
317            }
318            (t0, Self::TVar(t1)) if !t1.would_cycle(t0) => {
319                if let Some(t1) = &*t1.read().typ.read() {
320                    return t0.contains_int(env, hist, t1);
321                }
322                *t1.read().typ.write() = Some(t0.clone());
323                Ok(true)
324            }
325            (Self::Set(s0), Self::Set(s1))
326                if s0.as_ptr().addr() == s1.as_ptr().addr() =>
327            {
328                Ok(true)
329            }
330            (t0, Self::Set(s)) => Ok(s
331                .iter()
332                .map(|t1| t0.contains_int(env, hist, t1))
333                .collect::<Result<AndAc>>()?
334                .0),
335            (Self::Set(s), t) => Ok(s
336                .iter()
337                .fold(Ok::<_, anyhow::Error>(false), |acc, t0| {
338                    Ok(acc? || t0.contains_int(env, hist, t)?)
339                })?
340                || t.iter_prims().fold(Ok::<_, anyhow::Error>(true), |acc, t1| {
341                    Ok(acc?
342                        && s.iter().fold(Ok::<_, anyhow::Error>(false), |acc, t0| {
343                            Ok(acc? || t0.contains_int(env, hist, &t1)?)
344                        })?)
345                })?),
346            (Self::Fn(f0), Self::Fn(f1)) => {
347                Ok(f0.as_ptr() == f1.as_ptr() || f0.contains_int(env, hist, f1)?)
348            }
349            (_, Self::Any)
350            | (_, Self::TVar(_))
351            | (Self::TVar(_), _)
352            | (Self::Fn(_), _)
353            | (Self::ByRef(_), _)
354            | (_, Self::ByRef(_))
355            | (_, Self::Fn(_)) => Ok(false),
356        }
357    }
358
359    pub fn contains<R: Rt, E: UserEvent>(
360        &self,
361        env: &Env<R, E>,
362        t: &Self,
363    ) -> Result<bool> {
364        thread_local! {
365            static HIST: RefCell<FxHashMap<(usize, usize), bool>> = RefCell::new(HashMap::default());
366        }
367        HIST.with_borrow_mut(|hist| {
368            hist.clear();
369            self.contains_int(env, hist, t)
370        })
371    }
372
373    fn could_match_int<R: Rt, E: UserEvent>(
374        &self,
375        env: &Env<R, E>,
376        hist: &mut FxHashMap<(usize, usize), bool>,
377        t: &Self,
378    ) -> Result<bool> {
379        match (self, t) {
380            (
381                Self::Ref { scope: s0, name: n0, .. },
382                Self::Ref { scope: s1, name: n1, .. },
383            ) if s0 == s1 && n0 == n1 => Ok(true),
384            (t0 @ Self::Ref { .. }, t1) | (t0, t1 @ Self::Ref { .. }) => {
385                let t0 = t0.lookup_ref(env)?;
386                let t1 = t1.lookup_ref(env)?;
387                let t0_addr = (t0 as *const Type).addr();
388                let t1_addr = (t1 as *const Type).addr();
389                match hist.get(&(t0_addr, t1_addr)) {
390                    Some(r) => Ok(*r),
391                    None => {
392                        hist.insert((t0_addr, t1_addr), true);
393                        match t0.could_match_int(env, hist, t1) {
394                            Ok(r) => {
395                                hist.insert((t0_addr, t1_addr), r);
396                                Ok(r)
397                            }
398                            Err(e) => {
399                                hist.remove(&(t0_addr, t1_addr));
400                                Err(e)
401                            }
402                        }
403                    }
404                }
405            }
406            (t0, Self::Primitive(s)) => {
407                for t1 in s.iter() {
408                    if t0.contains_int(env, hist, &Type::Primitive(t1.into()))? {
409                        return Ok(true);
410                    }
411                }
412                Ok(false)
413            }
414            (t0, Self::Set(ts)) => {
415                for t1 in ts.iter() {
416                    if t0.contains_int(env, hist, t1)? {
417                        return Ok(true);
418                    }
419                }
420                Ok(false)
421            }
422            (Type::TVar(t0), t1) => match &*t0.read().typ.read() {
423                Some(t0) => t0.could_match_int(env, hist, t1),
424                None => Ok(false),
425            },
426            (t0, Type::TVar(t1)) => match &*t1.read().typ.read() {
427                Some(t1) => t0.could_match_int(env, hist, t1),
428                None => Ok(false),
429            },
430            (t0, t1) => t0.contains_int(env, hist, t1),
431        }
432    }
433
434    pub fn could_match<R: Rt, E: UserEvent>(
435        &self,
436        env: &Env<R, E>,
437        t: &Self,
438    ) -> Result<bool> {
439        thread_local! {
440            static HIST: RefCell<FxHashMap<(usize, usize), bool>> = RefCell::new(HashMap::default());
441        }
442        HIST.with_borrow_mut(|hist| {
443            hist.clear();
444            self.could_match_int(env, hist, t)
445        })
446    }
447
448    fn union_int<R: Rt, E: UserEvent>(
449        &self,
450        env: &Env<R, E>,
451        hist: &mut FxHashMap<(usize, usize), Type>,
452        t: &Self,
453    ) -> Result<Self> {
454        match (self, t) {
455            (
456                Type::Ref { name: n0, scope: s0, .. },
457                Type::Ref { scope: s1, name: n1, .. },
458            ) if n0 == n1 && s0 == s1 => Ok(self.clone()),
459            (tr @ Type::Ref { .. }, t) => {
460                let t0 = tr.lookup_ref(env)?;
461                let t0_addr = (t0 as *const Type).addr();
462                let t_addr = (t as *const Type).addr();
463                match hist.get(&(t0_addr, t_addr)) {
464                    Some(t) => Ok(t.clone()),
465                    None => {
466                        hist.insert((t0_addr, t_addr), tr.clone());
467                        let r = t0.union_int(env, hist, t)?;
468                        hist.insert((t0_addr, t_addr), r.clone());
469                        Ok(r)
470                    }
471                }
472            }
473            (t, tr @ Type::Ref { .. }) => {
474                let t1 = tr.lookup_ref(env)?;
475                let t1_addr = (t1 as *const Type).addr();
476                let t_addr = (t as *const Type).addr();
477                match hist.get(&(t_addr, t1_addr)) {
478                    Some(t) => Ok(t.clone()),
479                    None => {
480                        hist.insert((t_addr, t1_addr), tr.clone());
481                        let r = t.union_int(env, hist, t1)?;
482                        hist.insert((t_addr, t1_addr), r.clone());
483                        Ok(r)
484                    }
485                }
486            }
487            (Type::Bottom, t) | (t, Type::Bottom) => Ok(t.clone()),
488            (Type::Any, _) | (_, Type::Any) => Ok(Type::Any),
489            (Type::Primitive(p), t) | (t, Type::Primitive(p)) if p.is_empty() => {
490                Ok(t.clone())
491            }
492            (Type::Primitive(s0), Type::Primitive(s1)) => {
493                let mut s = *s0;
494                s.insert(*s1);
495                Ok(Type::Primitive(s))
496            }
497            (
498                Type::Primitive(p),
499                Type::Array(_) | Type::Struct(_) | Type::Tuple(_) | Type::Variant(_, _),
500            )
501            | (
502                Type::Array(_) | Type::Struct(_) | Type::Tuple(_) | Type::Variant(_, _),
503                Type::Primitive(p),
504            ) if p.contains(Typ::Array) => Ok(Type::Primitive(*p)),
505            (Type::Primitive(p), Type::Array(t))
506            | (Type::Array(t), Type::Primitive(p)) => Ok(Type::Set(Arc::from_iter([
507                Type::Primitive(*p),
508                Type::Array(t.clone()),
509            ]))),
510            (t @ Type::Array(t0), u @ Type::Array(t1)) => {
511                if t0 == t1 {
512                    Ok(Type::Array(t0.clone()))
513                } else {
514                    Ok(Type::Set(Arc::from_iter([u.clone(), t.clone()])))
515                }
516            }
517            (t @ Type::ByRef(t0), u @ Type::ByRef(t1)) => {
518                if t0 == t1 {
519                    Ok(Type::ByRef(t0.clone()))
520                } else {
521                    Ok(Type::Set(Arc::from_iter([u.clone(), t.clone()])))
522                }
523            }
524            (Type::Set(s0), Type::Set(s1)) => Ok(Type::Set(Arc::from_iter(
525                s0.iter().cloned().chain(s1.iter().cloned()),
526            ))),
527            (Type::Set(s), t) | (t, Type::Set(s)) => Ok(Type::Set(Arc::from_iter(
528                s.iter().cloned().chain(iter::once(t.clone())),
529            ))),
530            (u @ Type::Struct(t0), t @ Type::Struct(t1)) => {
531                if t0.len() == t1.len() && t0 == t1 {
532                    Ok(u.clone())
533                } else {
534                    Ok(Type::Set(Arc::from_iter([u.clone(), t.clone()])))
535                }
536            }
537            (u @ Type::Struct(_), t) | (t, u @ Type::Struct(_)) => {
538                Ok(Type::Set(Arc::from_iter([u.clone(), t.clone()])))
539            }
540            (u @ Type::Tuple(t0), t @ Type::Tuple(t1)) => {
541                if t0 == t1 {
542                    Ok(u.clone())
543                } else {
544                    Ok(Type::Set(Arc::from_iter([u.clone(), t.clone()])))
545                }
546            }
547            (u @ Type::Tuple(_), t) | (t, u @ Type::Tuple(_)) => {
548                Ok(Type::Set(Arc::from_iter([u.clone(), t.clone()])))
549            }
550            (u @ Type::Variant(tg0, t0), t @ Type::Variant(tg1, t1)) => {
551                if tg0 == tg1 && t0.len() == t1.len() {
552                    let typs = t0
553                        .iter()
554                        .zip(t1.iter())
555                        .map(|(t0, t1)| t0.union_int(env, hist, t1))
556                        .collect::<Result<SmallVec<[_; 8]>>>()?;
557                    Ok(Type::Variant(tg0.clone(), Arc::from_iter(typs.into_iter())))
558                } else {
559                    Ok(Type::Set(Arc::from_iter([u.clone(), t.clone()])))
560                }
561            }
562            (u @ Type::Variant(_, _), t) | (t, u @ Type::Variant(_, _)) => {
563                Ok(Type::Set(Arc::from_iter([u.clone(), t.clone()])))
564            }
565            (Type::Fn(f0), Type::Fn(f1)) => {
566                if f0 == f1 {
567                    Ok(Type::Fn(f0.clone()))
568                } else {
569                    Ok(Type::Set(Arc::from_iter([
570                        Type::Fn(f0.clone()),
571                        Type::Fn(f1.clone()),
572                    ])))
573                }
574            }
575            (f @ Type::Fn(_), t) | (t, f @ Type::Fn(_)) => {
576                Ok(Type::Set(Arc::from_iter([f.clone(), t.clone()])))
577            }
578            (t0 @ Type::TVar(_), t1 @ Type::TVar(_)) => {
579                if t0 == t1 {
580                    Ok(t0.clone())
581                } else {
582                    Ok(Type::Set(Arc::from_iter([t0.clone(), t1.clone()])))
583                }
584            }
585            (t0 @ Type::TVar(_), t1) | (t1, t0 @ Type::TVar(_)) => {
586                Ok(Type::Set(Arc::from_iter([t0.clone(), t1.clone()])))
587            }
588            (t @ Type::ByRef(_), u) | (u, t @ Type::ByRef(_)) => {
589                Ok(Type::Set(Arc::from_iter([t.clone(), u.clone()])))
590            }
591        }
592    }
593
594    pub fn union<R: Rt, E: UserEvent>(&self, env: &Env<R, E>, t: &Self) -> Result<Self> {
595        thread_local! {
596            static HIST: RefCell<FxHashMap<(usize, usize), Type>> = RefCell::new(HashMap::default());
597        }
598        HIST.with_borrow_mut(|hist| {
599            hist.clear();
600            Ok(self.union_int(env, hist, t)?.normalize())
601        })
602    }
603
604    fn diff_int<R: Rt, E: UserEvent>(
605        &self,
606        env: &Env<R, E>,
607        hist: &mut FxHashMap<(usize, usize), Type>,
608        t: &Self,
609    ) -> Result<Self> {
610        match (self, t) {
611            (Type::Any, _) => Ok(Type::Any),
612            (_, Type::Any) => Ok(Type::Primitive(BitFlags::empty())),
613            (
614                Type::Ref { scope: s0, name: n0, .. },
615                Type::Ref { scope: s1, name: n1, .. },
616            ) if s0 == s1 && n0 == n1 => Ok(Type::Primitive(BitFlags::empty())),
617            (t0 @ Type::Ref { .. }, t1) | (t0, t1 @ Type::Ref { .. }) => {
618                let t0 = t0.lookup_ref(env)?;
619                let t1 = t1.lookup_ref(env)?;
620                let t0_addr = (t0 as *const Type).addr();
621                let t1_addr = (t1 as *const Type).addr();
622                match hist.get(&(t0_addr, t1_addr)) {
623                    Some(r) => Ok(r.clone()),
624                    None => {
625                        let r = Type::Primitive(BitFlags::empty());
626                        hist.insert((t0_addr, t1_addr), r);
627                        match t0.diff_int(env, hist, &t1) {
628                            Ok(r) => {
629                                hist.insert((t0_addr, t1_addr), r.clone());
630                                Ok(r)
631                            }
632                            Err(e) => {
633                                hist.remove(&(t0_addr, t1_addr));
634                                Err(e)
635                            }
636                        }
637                    }
638                }
639            }
640            (Type::Bottom, t) | (t, Type::Bottom) => Ok(t.clone()),
641            (Type::Primitive(s0), Type::Primitive(s1)) => {
642                let mut s = *s0;
643                s.remove(*s1);
644                Ok(Type::Primitive(s))
645            }
646            (
647                Type::Primitive(p),
648                Type::Array(_) | Type::Struct(_) | Type::Tuple(_) | Type::Variant(_, _),
649            ) => {
650                // CR estokes: is this correct? It's a bit odd.
651                let mut s = *p;
652                s.remove(Typ::Array);
653                Ok(Type::Primitive(s))
654            }
655            (
656                Type::Array(_) | Type::Struct(_) | Type::Tuple(_) | Type::Variant(_, _),
657                Type::Primitive(p),
658            ) => {
659                if p.contains(Typ::Array) {
660                    Ok(Type::Primitive(BitFlags::empty()))
661                } else {
662                    Ok(self.clone())
663                }
664            }
665            (Type::Array(t0), Type::Array(t1)) => {
666                if t0 == t1 {
667                    Ok(Type::Primitive(BitFlags::empty()))
668                } else {
669                    Ok(Type::Array(Arc::new(t0.diff_int(env, hist, t1)?)))
670                }
671            }
672            (Type::ByRef(t0), Type::ByRef(t1)) => {
673                Ok(Type::ByRef(Arc::new(t0.diff_int(env, hist, t1)?)))
674            }
675            (Type::Set(s0), Type::Set(s1)) => {
676                let mut s: SmallVec<[Type; 4]> = smallvec![];
677                for i in 0..s0.len() {
678                    s.push(s0[i].clone());
679                    for j in 0..s1.len() {
680                        s[i] = s[i].diff_int(env, hist, &s1[j])?
681                    }
682                }
683                Ok(Self::flatten_set(s.into_iter()))
684            }
685            (Type::Set(s), t) => Ok(Self::flatten_set(
686                s.iter()
687                    .map(|s| s.diff_int(env, hist, t))
688                    .collect::<Result<SmallVec<[_; 8]>>>()?,
689            )),
690            (t, Type::Set(s)) => {
691                let mut t = t.clone();
692                for st in s.iter() {
693                    t = t.diff_int(env, hist, st)?;
694                }
695                Ok(t)
696            }
697            (Type::Tuple(t0), Type::Tuple(t1)) => {
698                if t0 == t1 {
699                    Ok(Type::Primitive(BitFlags::empty()))
700                } else {
701                    Ok(self.clone())
702                }
703            }
704            (Type::Tuple(_), _) | (_, Type::Tuple(_)) => Ok(self.clone()),
705            (Type::Struct(t0), Type::Struct(t1)) => {
706                if t0.len() == t1.len() && t0 == t1 {
707                    Ok(Type::Primitive(BitFlags::empty()))
708                } else {
709                    Ok(self.clone())
710                }
711            }
712            (Type::Struct(_), _) | (_, Type::Struct(_)) => Ok(self.clone()),
713            (Type::ByRef(_), _) | (_, Type::ByRef(_)) => Ok(self.clone()),
714            (Type::Variant(tg0, t0), Type::Variant(tg1, t1)) => {
715                if tg0 == tg1 && t0.len() == t1.len() && t0 == t1 {
716                    Ok(Type::Primitive(BitFlags::empty()))
717                } else {
718                    Ok(self.clone())
719                }
720            }
721            (Type::Variant(_, _), _) | (_, Type::Variant(_, _)) => Ok(self.clone()),
722            (Type::Fn(f0), Type::Fn(f1)) => {
723                if f0 == f1 {
724                    Ok(Type::Primitive(BitFlags::empty()))
725                } else {
726                    Ok(Type::Fn(f0.clone()))
727                }
728            }
729            (f @ Type::Fn(_), _) => Ok(f.clone()),
730            (t, Type::Fn(_)) => Ok(t.clone()),
731            (Type::TVar(tv0), Type::TVar(tv1)) => {
732                if tv0.read().typ.as_ptr() == tv1.read().typ.as_ptr() {
733                    return Ok(Type::Primitive(BitFlags::empty()));
734                }
735                Ok(match (&*tv0.read().typ.read(), &*tv1.read().typ.read()) {
736                    (None, _) | (_, None) => Type::TVar(tv0.clone()),
737                    (Some(t0), Some(t1)) => t0.diff_int(env, hist, t1)?,
738                })
739            }
740            (Type::TVar(tv), t1) => match &*tv.read().typ.read() {
741                None => Ok(Type::TVar(tv.clone())),
742                Some(t0) => t0.diff_int(env, hist, t1),
743            },
744            (t0, Type::TVar(tv)) => match &*tv.read().typ.read() {
745                None => Ok(t0.clone()),
746                Some(t1) => t0.diff_int(env, hist, t1),
747            },
748        }
749    }
750
751    pub fn diff<R: Rt, E: UserEvent>(&self, env: &Env<R, E>, t: &Self) -> Result<Self> {
752        thread_local! {
753            static HIST: RefCell<FxHashMap<(usize, usize), Type>> = RefCell::new(HashMap::default());
754        }
755        HIST.with_borrow_mut(|hist| {
756            hist.clear();
757            Ok(self.diff_int(env, hist, t)?.normalize())
758        })
759    }
760
761    pub fn any() -> Self {
762        Self::Any
763    }
764
765    pub fn boolean() -> Self {
766        Self::Primitive(Typ::Bool.into())
767    }
768
769    pub fn number() -> Self {
770        Self::Primitive(Typ::number())
771    }
772
773    pub fn int() -> Self {
774        Self::Primitive(Typ::integer())
775    }
776
777    pub fn uint() -> Self {
778        Self::Primitive(Typ::unsigned_integer())
779    }
780
781    /// alias type variables with the same name to each other
782    pub fn alias_tvars(&self, known: &mut FxHashMap<ArcStr, TVar>) {
783        match self {
784            Type::Bottom | Type::Any | Type::Primitive(_) => (),
785            Type::Ref { params, .. } => {
786                for t in params.iter() {
787                    t.alias_tvars(known);
788                }
789            }
790            Type::Array(t) => t.alias_tvars(known),
791            Type::ByRef(t) => t.alias_tvars(known),
792            Type::Tuple(ts) => {
793                for t in ts.iter() {
794                    t.alias_tvars(known)
795                }
796            }
797            Type::Struct(ts) => {
798                for (_, t) in ts.iter() {
799                    t.alias_tvars(known)
800                }
801            }
802            Type::Variant(_, ts) => {
803                for t in ts.iter() {
804                    t.alias_tvars(known)
805                }
806            }
807            Type::TVar(tv) => match known.entry(tv.name.clone()) {
808                Entry::Occupied(e) => {
809                    let v = e.get();
810                    v.freeze();
811                    tv.alias(v);
812                }
813                Entry::Vacant(e) => {
814                    e.insert(tv.clone());
815                    ()
816                }
817            },
818            Type::Fn(ft) => ft.alias_tvars(known),
819            Type::Set(s) => {
820                for typ in s.iter() {
821                    typ.alias_tvars(known)
822                }
823            }
824        }
825    }
826
827    pub fn collect_tvars(&self, known: &mut FxHashMap<ArcStr, TVar>) {
828        match self {
829            Type::Bottom | Type::Any | Type::Primitive(_) => (),
830            Type::Ref { params, .. } => {
831                for t in params.iter() {
832                    t.collect_tvars(known);
833                }
834            }
835            Type::Array(t) => t.collect_tvars(known),
836            Type::ByRef(t) => t.collect_tvars(known),
837            Type::Tuple(ts) => {
838                for t in ts.iter() {
839                    t.collect_tvars(known)
840                }
841            }
842            Type::Struct(ts) => {
843                for (_, t) in ts.iter() {
844                    t.collect_tvars(known)
845                }
846            }
847            Type::Variant(_, ts) => {
848                for t in ts.iter() {
849                    t.collect_tvars(known)
850                }
851            }
852            Type::TVar(tv) => match known.entry(tv.name.clone()) {
853                Entry::Occupied(_) => (),
854                Entry::Vacant(e) => {
855                    e.insert(tv.clone());
856                    ()
857                }
858            },
859            Type::Fn(ft) => ft.collect_tvars(known),
860            Type::Set(s) => {
861                for typ in s.iter() {
862                    typ.collect_tvars(known)
863                }
864            }
865        }
866    }
867
868    pub fn check_tvars_declared(&self, declared: &FxHashSet<ArcStr>) -> Result<()> {
869        match self {
870            Type::Bottom | Type::Any | Type::Primitive(_) => Ok(()),
871            Type::Ref { params, .. } => {
872                params.iter().try_for_each(|t| t.check_tvars_declared(declared))
873            }
874            Type::Array(t) => t.check_tvars_declared(declared),
875            Type::ByRef(t) => t.check_tvars_declared(declared),
876            Type::Tuple(ts) => {
877                ts.iter().try_for_each(|t| t.check_tvars_declared(declared))
878            }
879            Type::Struct(ts) => {
880                ts.iter().try_for_each(|(_, t)| t.check_tvars_declared(declared))
881            }
882            Type::Variant(_, ts) => {
883                ts.iter().try_for_each(|t| t.check_tvars_declared(declared))
884            }
885            Type::TVar(tv) => {
886                if !declared.contains(&tv.name) {
887                    bail!("undeclared type variable '{}'", tv.name)
888                } else {
889                    Ok(())
890                }
891            }
892            Type::Set(s) => s.iter().try_for_each(|t| t.check_tvars_declared(declared)),
893            Type::Fn(_) => Ok(()),
894        }
895    }
896
897    pub fn has_unbound(&self) -> bool {
898        match self {
899            Type::Bottom | Type::Any | Type::Primitive(_) => false,
900            Type::Ref { .. } => false,
901            Type::Array(t0) => t0.has_unbound(),
902            Type::ByRef(t0) => t0.has_unbound(),
903            Type::Tuple(ts) => ts.iter().any(|t| t.has_unbound()),
904            Type::Struct(ts) => ts.iter().any(|(_, t)| t.has_unbound()),
905            Type::Variant(_, ts) => ts.iter().any(|t| t.has_unbound()),
906            Type::TVar(tv) => tv.read().typ.read().is_some(),
907            Type::Set(s) => s.iter().any(|t| t.has_unbound()),
908            Type::Fn(ft) => ft.has_unbound(),
909        }
910    }
911
912    /// bind all unbound type variables to the specified type
913    pub fn bind_as(&self, t: &Self) {
914        match self {
915            Type::Bottom | Type::Any | Type::Primitive(_) => (),
916            Type::Ref { .. } => (),
917            Type::Array(t0) => t0.bind_as(t),
918            Type::ByRef(t0) => t0.bind_as(t),
919            Type::Tuple(ts) => {
920                for elt in ts.iter() {
921                    elt.bind_as(t)
922                }
923            }
924            Type::Struct(ts) => {
925                for (_, elt) in ts.iter() {
926                    elt.bind_as(t)
927                }
928            }
929            Type::Variant(_, ts) => {
930                for elt in ts.iter() {
931                    elt.bind_as(t)
932                }
933            }
934            Type::TVar(tv) => {
935                let tv = tv.read();
936                let mut tv = tv.typ.write();
937                if tv.is_none() {
938                    *tv = Some(t.clone());
939                }
940            }
941            Type::Set(s) => {
942                for elt in s.iter() {
943                    elt.bind_as(t)
944                }
945            }
946            Type::Fn(ft) => ft.bind_as(t),
947        }
948    }
949
950    /// return a copy of self with all type variables unbound and
951    /// unaliased. self will not be modified
952    pub fn reset_tvars(&self) -> Type {
953        match self {
954            Type::Bottom => Type::Bottom,
955            Type::Any => Type::Any,
956            Type::Primitive(p) => Type::Primitive(*p),
957            Type::Ref { scope, name, params } => Type::Ref {
958                scope: scope.clone(),
959                name: name.clone(),
960                params: Arc::from_iter(params.iter().map(|t| t.reset_tvars())),
961            },
962            Type::Array(t0) => Type::Array(Arc::new(t0.reset_tvars())),
963            Type::ByRef(t0) => Type::ByRef(Arc::new(t0.reset_tvars())),
964            Type::Tuple(ts) => {
965                Type::Tuple(Arc::from_iter(ts.iter().map(|t| t.reset_tvars())))
966            }
967            Type::Struct(ts) => Type::Struct(Arc::from_iter(
968                ts.iter().map(|(n, t)| (n.clone(), t.reset_tvars())),
969            )),
970            Type::Variant(tag, ts) => Type::Variant(
971                tag.clone(),
972                Arc::from_iter(ts.iter().map(|t| t.reset_tvars())),
973            ),
974            Type::TVar(tv) => Type::TVar(TVar::empty_named(tv.name.clone())),
975            Type::Set(s) => Type::Set(Arc::from_iter(s.iter().map(|t| t.reset_tvars()))),
976            Type::Fn(fntyp) => Type::Fn(Arc::new(fntyp.reset_tvars())),
977        }
978    }
979
980    /// return a copy of self with every TVar named in known replaced
981    /// with the corresponding type
982    pub fn replace_tvars(&self, known: &FxHashMap<ArcStr, Self>) -> Type {
983        match self {
984            Type::TVar(tv) => match known.get(&tv.name) {
985                Some(t) => t.clone(),
986                None => Type::TVar(tv.clone()),
987            },
988            Type::Bottom => Type::Bottom,
989            Type::Any => Type::Any,
990            Type::Primitive(p) => Type::Primitive(*p),
991            Type::Ref { scope, name, params } => Type::Ref {
992                scope: scope.clone(),
993                name: name.clone(),
994                params: Arc::from_iter(params.iter().map(|t| t.replace_tvars(known))),
995            },
996            Type::Array(t0) => Type::Array(Arc::new(t0.replace_tvars(known))),
997            Type::ByRef(t0) => Type::ByRef(Arc::new(t0.replace_tvars(known))),
998            Type::Tuple(ts) => {
999                Type::Tuple(Arc::from_iter(ts.iter().map(|t| t.replace_tvars(known))))
1000            }
1001            Type::Struct(ts) => Type::Struct(Arc::from_iter(
1002                ts.iter().map(|(n, t)| (n.clone(), t.replace_tvars(known))),
1003            )),
1004            Type::Variant(tag, ts) => Type::Variant(
1005                tag.clone(),
1006                Arc::from_iter(ts.iter().map(|t| t.replace_tvars(known))),
1007            ),
1008            Type::Set(s) => {
1009                Type::Set(Arc::from_iter(s.iter().map(|t| t.replace_tvars(known))))
1010            }
1011            Type::Fn(fntyp) => Type::Fn(Arc::new(fntyp.replace_tvars(known))),
1012        }
1013    }
1014
1015    /// Unbind any bound tvars, but do not unalias them.
1016    pub(crate) fn unbind_tvars(&self) {
1017        match self {
1018            Type::Bottom | Type::Any | Type::Primitive(_) | Type::Ref { .. } => (),
1019            Type::Array(t0) => t0.unbind_tvars(),
1020            Type::ByRef(t0) => t0.unbind_tvars(),
1021            Type::Tuple(ts) | Type::Variant(_, ts) | Type::Set(ts) => {
1022                for t in ts.iter() {
1023                    t.unbind_tvars()
1024                }
1025            }
1026            Type::Struct(ts) => {
1027                for (_, t) in ts.iter() {
1028                    t.unbind_tvars()
1029                }
1030            }
1031            Type::TVar(tv) => tv.unbind(),
1032            Type::Fn(fntyp) => fntyp.unbind_tvars(),
1033        }
1034    }
1035
1036    fn first_prim_int<R: Rt, E: UserEvent>(
1037        &self,
1038        env: &Env<R, E>,
1039        hist: &mut FxHashSet<usize>,
1040    ) -> Option<Typ> {
1041        match self {
1042            Type::Primitive(p) => p.iter().next(),
1043            Type::Set(s) => s.iter().find_map(|t| t.first_prim_int(env, hist)),
1044            Type::TVar(tv) => {
1045                tv.read().typ.read().as_ref().and_then(|t| t.first_prim_int(env, hist))
1046            }
1047            // array, tuple, and struct casting are handled directly
1048            Type::Bottom
1049            | Type::Any
1050            | Type::Fn(_)
1051            | Type::Array(_)
1052            | Type::Tuple(_)
1053            | Type::Struct(_)
1054            | Type::Variant(_, _)
1055            | Type::ByRef(_) => None,
1056            Type::Ref { .. } => {
1057                let t = self.lookup_ref(env).ok()?;
1058                let t_addr = (t as *const Type).addr();
1059                if hist.contains(&t_addr) {
1060                    None
1061                } else {
1062                    hist.insert(t_addr);
1063                    t.first_prim_int(env, hist)
1064                }
1065            }
1066        }
1067    }
1068
1069    fn first_prim<R: Rt, E: UserEvent>(&self, env: &Env<R, E>) -> Option<Typ> {
1070        thread_local! {
1071            static HIST: RefCell<FxHashSet<usize>> = RefCell::new(HashSet::default());
1072        }
1073        HIST.with_borrow_mut(|hist| {
1074            hist.clear();
1075            self.first_prim_int(env, hist)
1076        })
1077    }
1078
1079    fn check_cast_int<R: Rt, E: UserEvent>(
1080        &self,
1081        env: &Env<R, E>,
1082        hist: &mut FxHashSet<usize>,
1083    ) -> Result<()> {
1084        match self {
1085            Type::Primitive(_) | Type::Any => Ok(()),
1086            Type::Fn(_) => bail!("can't cast a value to a function"),
1087            Type::Bottom => bail!("can't cast a value to bottom"),
1088            Type::Set(s) => Ok(for t in s.iter() {
1089                t.check_cast_int(env, hist)?
1090            }),
1091            Type::TVar(tv) => match &*tv.read().typ.read() {
1092                Some(t) => t.check_cast_int(env, hist),
1093                None => bail!("can't cast a value to a free type variable"),
1094            },
1095            Type::Array(et) => et.check_cast_int(env, hist),
1096            Type::ByRef(_) => bail!("can't cast a reference"),
1097            Type::Tuple(ts) => Ok(for t in ts.iter() {
1098                t.check_cast_int(env, hist)?
1099            }),
1100            Type::Struct(ts) => Ok(for (_, t) in ts.iter() {
1101                t.check_cast_int(env, hist)?
1102            }),
1103            Type::Variant(_, ts) => Ok(for t in ts.iter() {
1104                t.check_cast_int(env, hist)?
1105            }),
1106            Type::Ref { .. } => {
1107                let t = self.lookup_ref(env)?;
1108                let t_addr = (t as *const Type).addr();
1109                if hist.contains(&t_addr) {
1110                    Ok(())
1111                } else {
1112                    hist.insert(t_addr);
1113                    t.check_cast_int(env, hist)
1114                }
1115            }
1116        }
1117    }
1118
1119    pub fn check_cast<R: Rt, E: UserEvent>(&self, env: &Env<R, E>) -> Result<()> {
1120        thread_local! {
1121            static HIST: RefCell<FxHashSet<usize>> = RefCell::new(FxHashSet::default());
1122        }
1123        HIST.with_borrow_mut(|hist| {
1124            hist.clear();
1125            self.check_cast_int(env, hist)
1126        })
1127    }
1128
1129    fn cast_value_int<R: Rt, E: UserEvent>(
1130        &self,
1131        env: &Env<R, E>,
1132        hist: &mut FxHashSet<usize>,
1133        v: Value,
1134    ) -> Result<Value> {
1135        if self.is_a_int(env, hist, &v) {
1136            return Ok(v);
1137        }
1138        match self {
1139            Type::Array(et) => match v {
1140                Value::Array(elts) => {
1141                    let va = elts
1142                        .iter()
1143                        .map(|el| et.cast_value_int(env, hist, el.clone()))
1144                        .collect::<Result<SmallVec<[Value; 8]>>>()?;
1145                    Ok(Value::Array(ValArray::from_iter_exact(va.into_iter())))
1146                }
1147                v => Ok(Value::Array([et.cast_value_int(env, hist, v)?].into())),
1148            },
1149            Type::Tuple(ts) => match v {
1150                Value::Array(elts) => {
1151                    if elts.len() != ts.len() {
1152                        bail!("tuple size mismatch {self} with {}", Value::Array(elts))
1153                    }
1154                    let a = ts
1155                        .iter()
1156                        .zip(elts.iter())
1157                        .map(|(t, el)| t.cast_value_int(env, hist, el.clone()))
1158                        .collect::<Result<SmallVec<[Value; 8]>>>()?;
1159                    Ok(Value::Array(ValArray::from_iter_exact(a.into_iter())))
1160                }
1161                v => bail!("can't cast {v} to {self}"),
1162            },
1163            Type::Struct(ts) => match v {
1164                Value::Array(elts) => {
1165                    if elts.len() != ts.len() {
1166                        bail!("struct size mismatch {self} with {}", Value::Array(elts))
1167                    }
1168                    let is_pairs = elts.iter().all(|v| match v {
1169                        Value::Array(a) if a.len() == 2 => match &a[0] {
1170                            Value::String(_) => true,
1171                            _ => false,
1172                        },
1173                        _ => false,
1174                    });
1175                    if !is_pairs {
1176                        bail!("expected array of pairs, got {}", Value::Array(elts))
1177                    }
1178                    let mut elts_s: SmallVec<[&Value; 16]> = elts.iter().collect();
1179                    elts_s.sort_by_key(|v| match v {
1180                        Value::Array(a) => match &a[0] {
1181                            Value::String(s) => s,
1182                            _ => unreachable!(),
1183                        },
1184                        _ => unreachable!(),
1185                    });
1186                    let (keys_ok, ok) = ts.iter().zip(elts_s.iter()).fold(
1187                        Ok((true, true)),
1188                        |acc: Result<_>, ((fname, t), v)| {
1189                            let (kok, ok) = acc?;
1190                            let (name, v) = match v {
1191                                Value::Array(a) => match (&a[0], &a[1]) {
1192                                    (Value::String(n), v) => (n, v),
1193                                    _ => unreachable!(),
1194                                },
1195                                _ => unreachable!(),
1196                            };
1197                            Ok((
1198                                kok && name == fname,
1199                                ok && kok
1200                                    && t.contains(
1201                                        env,
1202                                        &Type::Primitive(Typ::get(v).into()),
1203                                    )?,
1204                            ))
1205                        },
1206                    )?;
1207                    if ok {
1208                        drop(elts_s);
1209                        return Ok(Value::Array(elts));
1210                    } else if keys_ok {
1211                        let elts = ts
1212                            .iter()
1213                            .zip(elts_s.iter())
1214                            .map(|((n, t), v)| match v {
1215                                Value::Array(a) => {
1216                                    let a = [
1217                                        Value::String(n.clone()),
1218                                        t.cast_value_int(env, hist, a[1].clone())?,
1219                                    ];
1220                                    Ok(Value::Array(ValArray::from_iter_exact(
1221                                        a.into_iter(),
1222                                    )))
1223                                }
1224                                _ => unreachable!(),
1225                            })
1226                            .collect::<Result<SmallVec<[Value; 8]>>>()?;
1227                        Ok(Value::Array(ValArray::from_iter_exact(elts.into_iter())))
1228                    } else {
1229                        drop(elts_s);
1230                        bail!("struct fields mismatch {self}, {}", Value::Array(elts))
1231                    }
1232                }
1233                v => bail!("can't cast {v} to {self}"),
1234            },
1235            Type::Variant(tag, ts) if ts.len() == 0 => match &v {
1236                Value::String(s) if s == tag => Ok(v),
1237                _ => bail!("variant tag mismatch expected {tag} got {v}"),
1238            },
1239            Type::Variant(tag, ts) => match &v {
1240                Value::Array(elts) => {
1241                    if ts.len() + 1 == elts.len() {
1242                        match &elts[0] {
1243                            Value::String(s) if s == tag => (),
1244                            v => bail!("variant tag mismatch expected {tag} got {v}"),
1245                        }
1246                        let a = iter::once(&Type::Primitive(Typ::String.into()))
1247                            .chain(ts.iter())
1248                            .zip(elts.iter())
1249                            .map(|(t, v)| t.cast_value_int(env, hist, v.clone()))
1250                            .collect::<Result<SmallVec<[Value; 8]>>>()?;
1251                        Ok(Value::Array(ValArray::from_iter_exact(a.into_iter())))
1252                    } else if ts.len() == elts.len() {
1253                        let mut a = ts
1254                            .iter()
1255                            .zip(elts.iter())
1256                            .map(|(t, v)| t.cast_value_int(env, hist, v.clone()))
1257                            .collect::<Result<SmallVec<[Value; 8]>>>()?;
1258                        a.insert(0, Value::String(tag.clone()));
1259                        Ok(Value::Array(ValArray::from_iter_exact(a.into_iter())))
1260                    } else {
1261                        bail!("variant length mismatch")
1262                    }
1263                }
1264                v => bail!("can't cast {v} to {self}"),
1265            },
1266            Type::Ref { .. } => self.lookup_ref(env)?.cast_value_int(env, hist, v),
1267            t => match t.first_prim(env) {
1268                None => bail!("empty or non primitive cast"),
1269                Some(t) => Ok(v
1270                    .clone()
1271                    .cast(t)
1272                    .ok_or_else(|| anyhow!("can't cast {v} to {t}"))?),
1273            },
1274        }
1275    }
1276
1277    pub fn cast_value<R: Rt, E: UserEvent>(&self, env: &Env<R, E>, v: Value) -> Value {
1278        thread_local! {
1279            static HIST: RefCell<FxHashSet<usize>> = RefCell::new(HashSet::default());
1280        }
1281        HIST.with_borrow_mut(|hist| {
1282            hist.clear();
1283            match self.cast_value_int(env, hist, v) {
1284                Ok(v) => v,
1285                Err(e) => Value::Error(e.to_string().into()),
1286            }
1287        })
1288    }
1289
1290    fn is_a_int<R: Rt, E: UserEvent>(
1291        &self,
1292        env: &Env<R, E>,
1293        hist: &mut FxHashSet<usize>,
1294        v: &Value,
1295    ) -> bool {
1296        match self {
1297            Type::Ref { .. } => match self.lookup_ref(env) {
1298                Err(_) => false,
1299                Ok(t) => {
1300                    let t_addr = (t as *const Type).addr();
1301                    !hist.contains(&t_addr) && {
1302                        hist.insert(t_addr);
1303                        t.is_a_int(env, hist, v)
1304                    }
1305                }
1306            },
1307            Type::Primitive(t) => t.contains(Typ::get(&v)),
1308            Type::Any => true,
1309            Type::Array(et) => match v {
1310                Value::Array(a) => a.iter().all(|v| et.is_a_int(env, hist, v)),
1311                _ => false,
1312            },
1313            Type::ByRef(_) => matches!(v, Value::U64(_) | Value::V64(_)),
1314            Type::Tuple(ts) => match v {
1315                Value::Array(elts) => {
1316                    elts.len() == ts.len()
1317                        && ts
1318                            .iter()
1319                            .zip(elts.iter())
1320                            .all(|(t, v)| t.is_a_int(env, hist, v))
1321                }
1322                _ => false,
1323            },
1324            Type::Struct(ts) => match v {
1325                Value::Array(elts) => {
1326                    elts.len() == ts.len()
1327                        && ts.iter().zip(elts.iter()).all(|((n, t), v)| match v {
1328                            Value::Array(a) if a.len() == 2 => match &a[..] {
1329                                [Value::String(key), v] => {
1330                                    n == key && t.is_a_int(env, hist, v)
1331                                }
1332                                _ => false,
1333                            },
1334                            _ => false,
1335                        })
1336                }
1337                _ => false,
1338            },
1339            Type::Variant(tag, ts) if ts.len() == 0 => match &v {
1340                Value::String(s) => s == tag,
1341                _ => false,
1342            },
1343            Type::Variant(tag, ts) => match &v {
1344                Value::Array(elts) => {
1345                    ts.len() + 1 == elts.len()
1346                        && match &elts[0] {
1347                            Value::String(s) => s == tag,
1348                            _ => false,
1349                        }
1350                        && ts
1351                            .iter()
1352                            .zip(elts[1..].iter())
1353                            .all(|(t, v)| t.is_a_int(env, hist, v))
1354                }
1355                _ => false,
1356            },
1357            Type::TVar(tv) => match &*tv.read().typ.read() {
1358                None => true,
1359                Some(t) => t.is_a_int(env, hist, v),
1360            },
1361            Type::Fn(_) => match v {
1362                Value::U64(_) => true,
1363                _ => false,
1364            },
1365            Type::Bottom => true,
1366            Type::Set(ts) => ts.iter().any(|t| t.is_a_int(env, hist, v)),
1367        }
1368    }
1369
1370    /// return true if v is structurally compatible with the type
1371    pub fn is_a<R: Rt, E: UserEvent>(&self, env: &Env<R, E>, v: &Value) -> bool {
1372        thread_local! {
1373            static HIST: RefCell<FxHashSet<usize>> = RefCell::new(HashSet::default());
1374        }
1375        HIST.with_borrow_mut(|hist| {
1376            hist.clear();
1377            self.is_a_int(env, hist, v)
1378        })
1379    }
1380
1381    pub fn is_bot(&self) -> bool {
1382        match self {
1383            Type::Bottom => true,
1384            Type::Any
1385            | Type::TVar(_)
1386            | Type::Primitive(_)
1387            | Type::Ref { .. }
1388            | Type::Fn(_)
1389            | Type::Array(_)
1390            | Type::ByRef(_)
1391            | Type::Tuple(_)
1392            | Type::Struct(_)
1393            | Type::Variant(_, _)
1394            | Type::Set(_) => false,
1395        }
1396    }
1397
1398    pub fn with_deref<R, F: FnOnce(Option<&Self>) -> R>(&self, f: F) -> R {
1399        match self {
1400            Self::Bottom
1401            | Self::Any
1402            | Self::Primitive(_)
1403            | Self::Fn(_)
1404            | Self::Set(_)
1405            | Self::Array(_)
1406            | Self::ByRef(_)
1407            | Self::Tuple(_)
1408            | Self::Struct(_)
1409            | Self::Variant(_, _)
1410            | Self::Ref { .. } => f(Some(self)),
1411            Self::TVar(tv) => f(tv.read().typ.read().as_ref()),
1412        }
1413    }
1414
1415    pub(crate) fn flatten_set(set: impl IntoIterator<Item = Self>) -> Self {
1416        let init: Box<dyn Iterator<Item = Self>> = Box::new(set.into_iter());
1417        let mut iters: SmallVec<[Box<dyn Iterator<Item = Self>>; 16]> = smallvec![init];
1418        let mut acc: SmallVec<[Self; 16]> = smallvec![];
1419        loop {
1420            match iters.last_mut() {
1421                None => break,
1422                Some(iter) => match iter.next() {
1423                    None => {
1424                        iters.pop();
1425                    }
1426                    Some(Type::Set(s)) => {
1427                        let v: SmallVec<[Self; 16]> =
1428                            s.iter().map(|t| t.clone()).collect();
1429                        iters.push(Box::new(v.into_iter()))
1430                    }
1431                    Some(Type::Any) => return Type::Any,
1432                    Some(t) => {
1433                        acc.push(t);
1434                        let mut i = 0;
1435                        let mut j;
1436                        while i < acc.len() {
1437                            j = i + 1;
1438                            while j < acc.len() {
1439                                if let Some(t) = acc[i].merge(&acc[j]) {
1440                                    acc[i] = t;
1441                                    acc.remove(j);
1442                                } else {
1443                                    j += 1;
1444                                }
1445                            }
1446                            i += 1;
1447                        }
1448                    }
1449                },
1450            }
1451        }
1452        acc.sort();
1453        match &*acc {
1454            [] => Type::Primitive(BitFlags::empty()),
1455            [t] => t.clone(),
1456            _ => Type::Set(Arc::from_iter(acc)),
1457        }
1458    }
1459
1460    pub(crate) fn normalize(&self) -> Self {
1461        match self {
1462            Type::Bottom | Type::Any | Type::Primitive(_) => self.clone(),
1463            Type::Ref { scope, name, params } => {
1464                let params = Arc::from_iter(params.iter().map(|t| t.normalize()));
1465                Type::Ref { scope: scope.clone(), name: name.clone(), params }
1466            }
1467            Type::TVar(tv) => Type::TVar(tv.normalize()),
1468            Type::Set(s) => Self::flatten_set(s.iter().map(|t| t.normalize())),
1469            Type::Array(t) => Type::Array(Arc::new(t.normalize())),
1470            Type::ByRef(t) => Type::ByRef(Arc::new(t.normalize())),
1471            Type::Tuple(t) => {
1472                Type::Tuple(Arc::from_iter(t.iter().map(|t| t.normalize())))
1473            }
1474            Type::Struct(t) => Type::Struct(Arc::from_iter(
1475                t.iter().map(|(n, t)| (n.clone(), t.normalize())),
1476            )),
1477            Type::Variant(tag, t) => Type::Variant(
1478                tag.clone(),
1479                Arc::from_iter(t.iter().map(|t| t.normalize())),
1480            ),
1481            Type::Fn(ft) => Type::Fn(Arc::new(ft.normalize())),
1482        }
1483    }
1484
1485    fn merge(&self, t: &Self) -> Option<Self> {
1486        match (self, t) {
1487            (
1488                Type::Ref { scope: s0, name: r0, params: a0 },
1489                Type::Ref { scope: s1, name: r1, params: a1 },
1490            ) => {
1491                if s0 == s1 && r0 == r1 && a0 == a1 {
1492                    Some(Type::Ref {
1493                        scope: s0.clone(),
1494                        name: r0.clone(),
1495                        params: a0.clone(),
1496                    })
1497                } else {
1498                    None
1499                }
1500            }
1501            (Type::Ref { .. }, _) | (_, Type::Ref { .. }) => None,
1502            (Type::Bottom, t) | (t, Type::Bottom) => Some(t.clone()),
1503            (Type::Any, _) | (_, Type::Any) => Some(Type::Any),
1504            (Type::Primitive(p), t) | (t, Type::Primitive(p)) if p.is_empty() => {
1505                Some(t.clone())
1506            }
1507            (Type::Primitive(s0), Type::Primitive(s1)) => {
1508                let mut s = *s0;
1509                s.insert(*s1);
1510                Some(Type::Primitive(s))
1511            }
1512            (Type::Fn(f0), Type::Fn(f1)) => {
1513                if f0 == f1 {
1514                    Some(Type::Fn(f0.clone()))
1515                } else {
1516                    None
1517                }
1518            }
1519            (Type::Array(t0), Type::Array(t1)) => {
1520                let t0f = match &**t0 {
1521                    Type::Set(et) => Self::flatten_set(et.iter().cloned()),
1522                    t => t.clone(),
1523                };
1524                let t1f = match &**t1 {
1525                    Type::Set(et) => Self::flatten_set(et.iter().cloned()),
1526                    t => t.clone(),
1527                };
1528                if t0f == t1f {
1529                    Some(Type::Array(t0.clone()))
1530                } else {
1531                    None
1532                }
1533            }
1534            (Type::ByRef(t0), Type::ByRef(t1)) => {
1535                t0.merge(t1).map(|t| Type::ByRef(Arc::new(t)))
1536            }
1537            (Type::ByRef(_), _) | (_, Type::ByRef(_)) => None,
1538            (Type::Array(_), _) | (_, Type::Array(_)) => None,
1539            (Type::Set(s0), Type::Set(s1)) => {
1540                Some(Self::flatten_set(s0.iter().cloned().chain(s1.iter().cloned())))
1541            }
1542            (Type::Set(s), Type::Primitive(p)) | (Type::Primitive(p), Type::Set(s))
1543                if p.is_empty() =>
1544            {
1545                Some(Type::Set(s.clone()))
1546            }
1547            (Type::Set(s), t) | (t, Type::Set(s)) => {
1548                Some(Self::flatten_set(s.iter().cloned().chain(iter::once(t.clone()))))
1549            }
1550            (Type::Tuple(t0), Type::Tuple(t1)) => {
1551                if t0.len() == t1.len() {
1552                    let t = t0
1553                        .iter()
1554                        .zip(t1.iter())
1555                        .map(|(t0, t1)| t0.merge(t1))
1556                        .collect::<Option<SmallVec<[Type; 8]>>>()?;
1557                    Some(Type::Tuple(Arc::from_iter(t)))
1558                } else {
1559                    None
1560                }
1561            }
1562            (Type::Variant(tag0, t0), Type::Variant(tag1, t1)) => {
1563                if tag0 == tag1 && t0.len() == t1.len() {
1564                    let t = t0
1565                        .iter()
1566                        .zip(t1.iter())
1567                        .map(|(t0, t1)| t0.merge(t1))
1568                        .collect::<Option<SmallVec<[Type; 8]>>>()?;
1569                    Some(Type::Variant(tag0.clone(), Arc::from_iter(t)))
1570                } else {
1571                    None
1572                }
1573            }
1574            (Type::Struct(t0), Type::Struct(t1)) => {
1575                if t0.len() == t1.len() {
1576                    let t = t0
1577                        .iter()
1578                        .zip(t1.iter())
1579                        .map(|((n0, t0), (n1, t1))| {
1580                            if n0 != n1 {
1581                                None
1582                            } else {
1583                                t0.merge(t1).map(|t| (n0.clone(), t))
1584                            }
1585                        })
1586                        .collect::<Option<SmallVec<[(ArcStr, Type); 8]>>>()?;
1587                    Some(Type::Struct(Arc::from_iter(t)))
1588                } else {
1589                    None
1590                }
1591            }
1592            (Type::TVar(tv0), Type::TVar(tv1)) if tv0.name == tv1.name && tv0 == tv1 => {
1593                Some(Type::TVar(tv0.clone()))
1594            }
1595            (Type::TVar(tv), t) => {
1596                tv.read().typ.read().as_ref().and_then(|tv| tv.merge(t))
1597            }
1598            (t, Type::TVar(tv)) => {
1599                tv.read().typ.read().as_ref().and_then(|tv| t.merge(tv))
1600            }
1601            (Type::Tuple(_), _)
1602            | (_, Type::Tuple(_))
1603            | (Type::Struct(_), _)
1604            | (_, Type::Struct(_))
1605            | (Type::Variant(_, _), _)
1606            | (_, Type::Variant(_, _))
1607            | (_, Type::Fn(_))
1608            | (Type::Fn(_), _) => None,
1609        }
1610    }
1611
1612    pub fn scope_refs(&self, scope: &ModPath) -> Type {
1613        match self {
1614            Type::Bottom => Type::Bottom,
1615            Type::Any => Type::Any,
1616            Type::Primitive(s) => Type::Primitive(*s),
1617            Type::Array(t0) => Type::Array(Arc::new(t0.scope_refs(scope))),
1618            Type::ByRef(t) => Type::ByRef(Arc::new(t.scope_refs(scope))),
1619            Type::Tuple(ts) => {
1620                let i = ts.iter().map(|t| t.scope_refs(scope));
1621                Type::Tuple(Arc::from_iter(i))
1622            }
1623            Type::Variant(tag, ts) => {
1624                let i = ts.iter().map(|t| t.scope_refs(scope));
1625                Type::Variant(tag.clone(), Arc::from_iter(i))
1626            }
1627            Type::Struct(ts) => {
1628                let i = ts.iter().map(|(n, t)| (n.clone(), t.scope_refs(scope)));
1629                Type::Struct(Arc::from_iter(i))
1630            }
1631            Type::TVar(tv) => match tv.read().typ.read().as_ref() {
1632                None => Type::TVar(TVar::empty_named(tv.name.clone())),
1633                Some(typ) => {
1634                    let typ = typ.scope_refs(scope);
1635                    Type::TVar(TVar::named(tv.name.clone(), typ))
1636                }
1637            },
1638            Type::Ref { scope: _, name, params } => {
1639                let params = Arc::from_iter(params.iter().map(|t| t.scope_refs(scope)));
1640                Type::Ref { scope: scope.clone(), name: name.clone(), params }
1641            }
1642            Type::Set(ts) => {
1643                Type::Set(Arc::from_iter(ts.iter().map(|t| t.scope_refs(scope))))
1644            }
1645            Type::Fn(f) => {
1646                let vargs = f.vargs.as_ref().map(|t| t.scope_refs(scope));
1647                let rtype = f.rtype.scope_refs(scope);
1648                let args = Arc::from_iter(f.args.iter().map(|a| FnArgType {
1649                    label: a.label.clone(),
1650                    typ: a.typ.scope_refs(scope),
1651                }));
1652                let mut cres: SmallVec<[(TVar, Type); 4]> = smallvec![];
1653                for (tv, tc) in f.constraints.read().iter() {
1654                    let tv = tv.scope_refs(scope);
1655                    let tc = tc.scope_refs(scope);
1656                    cres.push((tv, tc));
1657                }
1658                Type::Fn(Arc::new(FnType {
1659                    args,
1660                    rtype,
1661                    constraints: Arc::new(RwLock::new(cres.into_iter().collect())),
1662                    vargs,
1663                }))
1664            }
1665        }
1666    }
1667}
1668
1669impl fmt::Display for Type {
1670    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1671        match self {
1672            Self::Bottom => write!(f, "_"),
1673            Self::Any => write!(f, "Any"),
1674            Self::Ref { scope: _, name, params } => {
1675                write!(f, "{name}")?;
1676                if !params.is_empty() {
1677                    write!(f, "<")?;
1678                    for (i, t) in params.iter().enumerate() {
1679                        write!(f, "{t}")?;
1680                        if i < params.len() - 1 {
1681                            write!(f, ", ")?;
1682                        }
1683                    }
1684                    write!(f, ">")?;
1685                }
1686                Ok(())
1687            }
1688            Self::TVar(tv) => write!(f, "{tv}"),
1689            Self::Fn(t) => write!(f, "{t}"),
1690            Self::Array(t) => write!(f, "Array<{t}>"),
1691            Self::ByRef(t) => write!(f, "&{t}"),
1692            Self::Tuple(ts) => {
1693                write!(f, "(")?;
1694                for (i, t) in ts.iter().enumerate() {
1695                    write!(f, "{t}")?;
1696                    if i < ts.len() - 1 {
1697                        write!(f, ", ")?;
1698                    }
1699                }
1700                write!(f, ")")
1701            }
1702            Self::Variant(tag, ts) if ts.len() == 0 => {
1703                write!(f, "`{tag}")
1704            }
1705            Self::Variant(tag, ts) => {
1706                write!(f, "`{tag}(")?;
1707                for (i, t) in ts.iter().enumerate() {
1708                    write!(f, "{t}")?;
1709                    if i < ts.len() - 1 {
1710                        write!(f, ", ")?
1711                    }
1712                }
1713                write!(f, ")")
1714            }
1715            Self::Struct(ts) => {
1716                write!(f, "{{")?;
1717                for (i, (n, t)) in ts.iter().enumerate() {
1718                    write!(f, "{n}: {t}")?;
1719                    if i < ts.len() - 1 {
1720                        write!(f, ", ")?
1721                    }
1722                }
1723                write!(f, "}}")
1724            }
1725            Self::Set(s) => {
1726                write!(f, "[")?;
1727                for (i, t) in s.iter().enumerate() {
1728                    write!(f, "{t}")?;
1729                    if i < s.len() - 1 {
1730                        write!(f, ", ")?;
1731                    }
1732                }
1733                write!(f, "]")
1734            }
1735            Self::Primitive(s) => {
1736                let replace = PRINT_FLAGS.get().contains(PrintFlag::ReplacePrims);
1737                if replace && *s == Typ::number() {
1738                    write!(f, "Number")
1739                } else if replace && *s == Typ::float() {
1740                    write!(f, "Float")
1741                } else if replace && *s == Typ::real() {
1742                    write!(f, "Real")
1743                } else if replace && *s == Typ::integer() {
1744                    write!(f, "Int")
1745                } else if replace && *s == Typ::unsigned_integer() {
1746                    write!(f, "Uint")
1747                } else if replace && *s == Typ::signed_integer() {
1748                    write!(f, "Sint")
1749                } else if s.len() == 0 {
1750                    write!(f, "[]")
1751                } else if s.len() == 1 {
1752                    write!(f, "{}", s.iter().next().unwrap())
1753                } else {
1754                    let mut s = *s;
1755                    macro_rules! builtin {
1756                        ($set:expr, $name:literal) => {
1757                            if replace && s.contains($set) {
1758                                s.remove($set);
1759                                write!(f, $name)?;
1760                                if !s.is_empty() {
1761                                    write!(f, ", ")?
1762                                }
1763                            }
1764                        };
1765                    }
1766                    write!(f, "[")?;
1767                    builtin!(Typ::number(), "Number");
1768                    builtin!(Typ::real(), "Real");
1769                    builtin!(Typ::float(), "Float");
1770                    builtin!(Typ::integer(), "Int");
1771                    builtin!(Typ::unsigned_integer(), "Uint");
1772                    builtin!(Typ::signed_integer(), "Sint");
1773                    for (i, t) in s.iter().enumerate() {
1774                        write!(f, "{t}")?;
1775                        if i < s.len() - 1 {
1776                            write!(f, ", ")?;
1777                        }
1778                    }
1779                    write!(f, "]")
1780                }
1781            }
1782        }
1783    }
1784}