tinymist_analysis/ty/
def.rs

1//! Name Convention:
2//! - `TypeXXX`: abstracted types or clauses
3//! - `XXTy`: concrete types
4
5use core::fmt;
6use std::{
7    hash::{Hash, Hasher},
8    sync::{Arc, OnceLock},
9};
10
11use ecow::EcoString;
12use parking_lot::{Mutex, RwLock};
13use rustc_hash::{FxHashMap, FxHashSet};
14use serde::{Deserialize, Serialize};
15use typst::{
16    foundations::{Content, Element, ParamInfo, Type, Value},
17    syntax::{FileId, Span, SyntaxKind, SyntaxNode, ast},
18};
19
20use super::{BoundPred, BuiltinTy, PackageId};
21use crate::{
22    adt::{interner::impl_internable, snapshot_map},
23    docs::UntypedDefDocs,
24    syntax::{DeclExpr, UnaryOp},
25};
26
27pub(crate) use super::{TyCtx, TyCtxMut};
28pub(crate) use crate::adt::interner::Interned;
29pub use tinymist_derive::BindTyCtx;
30
31/// A reference to the interned type.
32pub(crate) type TyRef = Interned<Ty>;
33/// A reference to the interned string.
34pub(crate) type StrRef = Interned<str>;
35
36/// All possible types in tinymist.
37#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
38pub enum Ty {
39    // Simple Types
40    /// A top type, whose negation is bottom type.
41    /// `t := top, t^- := bottom`
42    Any,
43    /// A boolean type, can be `false`, `true`, or both (boolean type).
44    /// `t := false | true`
45    Boolean(Option<bool>),
46    /// All possible types in typst.
47    Builtin(BuiltinTy),
48    /// A possible typst instance of some type.
49    Value(Interned<InsTy>),
50    /// A parameter type
51    Param(Interned<ParamTy>),
52
53    // Combination Types
54    /// A union type, whose negation is intersection type.
55    /// `t := t1 | t2 | ... | tn, t^- := t1 & t2 & ... & tn`
56    Union(Interned<Vec<Ty>>),
57    /// A frozen type variable.
58    /// `t :> t1 | t2 | ... | tn <: f1 & f2 & ... & fn`
59    Let(Interned<TypeBounds>),
60    /// An opening type variable owing bounds.
61    Var(Interned<TypeVar>),
62
63    // Composite Types
64    /// A typst dictionary type.
65    Dict(Interned<RecordTy>),
66    /// An array type.
67    Array(TyRef),
68    /// A tuple type.
69    /// Note: may contains spread types.
70    Tuple(Interned<Vec<Ty>>),
71    /// A function type.
72    Func(Interned<SigTy>),
73    /// An argument type.
74    Args(Interned<ArgsTy>),
75    /// A pattern type.
76    Pattern(Interned<PatternTy>),
77
78    // Type operations
79    /// A partially applied function type.
80    With(Interned<SigWithTy>),
81    /// Select a field from a type.
82    Select(Interned<SelectTy>),
83    /// A unary operation.
84    Unary(Interned<TypeUnary>),
85    /// A binary operation.
86    Binary(Interned<TypeBinary>),
87    /// A conditional type.
88    If(Interned<IfTy>),
89}
90
91impl fmt::Debug for Ty {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        match self {
94            Ty::Any => f.write_str("Any"),
95            Ty::Builtin(ty) => write!(f, "{ty:?}"),
96            Ty::Args(args) => write!(f, "&({args:?})"),
97            Ty::Func(func) => write!(f, "{func:?}"),
98            Ty::Pattern(pat) => write!(f, "{pat:?}"),
99            Ty::Dict(record) => write!(f, "{record:?}"),
100            Ty::Array(arr) => write!(f, "Array<{arr:?}>"),
101            Ty::Tuple(elems) => {
102                f.write_str("(")?;
103                for t in elems.iter() {
104                    write!(f, "{t:?}, ")?;
105                }
106                f.write_str(")")
107            }
108            Ty::With(with) => write!(f, "({:?}).with(..{:?})", with.sig, with.with),
109            Ty::Select(sel) => write!(f, "{sel:?}"),
110            Ty::Union(types) => {
111                f.write_str("(")?;
112                if let Some((first, u)) = types.split_first() {
113                    write!(f, "{first:?}")?;
114                    for u in u {
115                        write!(f, " | {u:?}")?;
116                    }
117                }
118                f.write_str(")")
119            }
120            Ty::Let(bounds) => write!(f, "({bounds:?})"),
121            Ty::Param(param) => write!(f, "{:?}: {:?}", param.name, param.ty),
122            Ty::Var(var) => var.fmt(f),
123            Ty::Unary(unary) => write!(f, "{unary:?}"),
124            Ty::Binary(binary) => write!(f, "{binary:?}"),
125            Ty::If(if_expr) => write!(f, "{if_expr:?}"),
126            Ty::Value(ins_ty) => write!(f, "{:?}", ins_ty.val),
127            Ty::Boolean(truthiness) => {
128                if let Some(truthiness) = truthiness {
129                    write!(f, "{truthiness}")
130                } else {
131                    f.write_str("Boolean")
132                }
133            }
134        }
135    }
136}
137
138impl Ty {
139    /// Whether the type is a dictionary type.
140    pub fn is_dict(&self) -> bool {
141        matches!(self, Ty::Dict(..))
142    }
143
144    /// Creates a union type from two types.
145    pub fn union(lhs: Option<Ty>, rhs: Option<Ty>) -> Option<Ty> {
146        Some(match (lhs, rhs) {
147            (Some(lhs), Some(rhs)) => Ty::from_types([lhs, rhs].into_iter()),
148            (Some(ty), None) | (None, Some(ty)) => ty,
149            (None, None) => return None,
150        })
151    }
152
153    /// Creates a union type from an iterator of types.
154    pub fn from_types(iter: impl ExactSizeIterator<Item = Ty>) -> Self {
155        if iter.len() == 0 {
156            Ty::Any
157        } else if iter.len() == 1 {
158            let mut iter = iter;
159            iter.next().unwrap()
160        } else {
161            Self::iter_union(iter)
162        }
163    }
164
165    /// Creates a union type from an iterator of types.     
166    pub fn iter_union(iter: impl IntoIterator<Item = Ty>) -> Self {
167        let mut v: Vec<Ty> = iter.into_iter().collect();
168        v.sort();
169        Ty::Union(Interned::new(v))
170    }
171
172    /// Creates an undefined type (which will emit an error).
173    /// A that type is annotated if the syntax structure causes an type error.
174    pub const fn undef() -> Self {
175        Ty::Builtin(BuiltinTy::Undef)
176    }
177
178    /// Gets the name of the type.
179    pub fn name(&self) -> Interned<str> {
180        match self {
181            Ty::Var(v) => v.name.clone(),
182            Ty::Builtin(BuiltinTy::Module(m)) => m.name().clone(),
183            ty => ty
184                .value()
185                .map(|_| Interned::new_str(&self.name()))
186                .unwrap_or_default(),
187        }
188    }
189
190    /// Gets the span of the type.
191    pub fn span(&self) -> Span {
192        fn seq(u: &[Ty]) -> Option<Span> {
193            u.iter().find_map(|ty| {
194                let sub = ty.span();
195                if sub.is_detached() {
196                    return None;
197                }
198                Some(sub)
199            })
200        }
201
202        match self {
203            Ty::Var(v) => v.def.span(),
204            Ty::Let(u) => seq(&u.ubs)
205                .or_else(|| seq(&u.lbs))
206                .unwrap_or_else(Span::detached),
207            Ty::Union(u) => seq(u).unwrap_or_else(Span::detached),
208            _ => Span::detached(),
209        }
210    }
211
212    /// Gets the value repr of the type.
213    pub fn value(&self) -> Option<Value> {
214        match self {
215            Ty::Value(v) => Some(v.val.clone()),
216            Ty::Builtin(BuiltinTy::Element(v)) => Some(Value::Func((*v).into())),
217            Ty::Builtin(BuiltinTy::Type(ty)) => Some(Value::Type(*ty)),
218            _ => None,
219        }
220    }
221
222    /// Gets the element type.
223    pub fn element(&self) -> Option<Element> {
224        match self {
225            Ty::Value(ins_ty) => match &ins_ty.val {
226                Value::Func(func) => func.element(),
227                _ => None,
228            },
229            Ty::Builtin(BuiltinTy::Element(v)) => Some(*v),
230            _ => None,
231        }
232    }
233
234    /// Checks a type against a context.
235    pub fn satisfy<T: TyCtx>(&self, ctx: &T, f: impl FnMut(&Ty, bool)) {
236        self.bounds(true, &mut BoundPred::new(ctx, f));
237    }
238
239    /// Checks if the type is a content type.
240    pub fn is_content<T: TyCtx>(&self, ctx: &T) -> bool {
241        let mut res = false;
242        self.satisfy(ctx, |ty: &Ty, _pol| {
243            res = res || {
244                match ty {
245                    Ty::Value(v) => is_content_builtin_type(&v.val.ty()),
246                    Ty::Builtin(BuiltinTy::Content(..)) => true,
247                    Ty::Builtin(BuiltinTy::Type(v)) => is_content_builtin_type(v),
248                    _ => false,
249                }
250            }
251        });
252        res
253    }
254
255    /// Checks if the type is a string type.
256    pub fn is_str<T: TyCtx>(&self, ctx: &T) -> bool {
257        let mut res = false;
258        self.satisfy(ctx, |ty: &Ty, _pol| {
259            res = res || {
260                match ty {
261                    Ty::Value(v) => is_str_builtin_type(&v.val.ty()),
262                    Ty::Builtin(BuiltinTy::Type(v)) => is_str_builtin_type(v),
263                    _ => false,
264                }
265            }
266        });
267        res
268    }
269
270    /// Checks if the type is a type type.
271    pub fn is_type<T: TyCtx>(&self, ctx: &T) -> bool {
272        let mut res = false;
273        self.satisfy(ctx, |ty: &Ty, _pol| {
274            res = res || {
275                match ty {
276                    Ty::Value(v) => is_type_builtin_type(&v.val.ty()),
277                    Ty::Builtin(BuiltinTy::Type(ty)) => is_type_builtin_type(ty),
278                    Ty::Builtin(BuiltinTy::TypeType(..)) => true,
279                    _ => false,
280                }
281            }
282        });
283        res
284    }
285}
286
287/// Checks if the type is a content builtin type.
288fn is_content_builtin_type(ty: &Type) -> bool {
289    *ty == Type::of::<Content>() || *ty == Type::of::<typst::foundations::Symbol>()
290}
291
292/// Checks if the type is a string builtin type.
293fn is_str_builtin_type(ty: &Type) -> bool {
294    *ty == Type::of::<typst::foundations::Str>()
295}
296
297/// Checks if the type is a type builtin type.
298fn is_type_builtin_type(ty: &Type) -> bool {
299    *ty == Type::of::<Type>()
300}
301
302/// A function parameter type.
303pub enum TypeSigParam<'a> {
304    /// A positional parameter: `a`
305    Pos(&'a Ty),
306    /// A named parameter: `b: c`
307    Named(&'a StrRef, &'a Ty),
308    /// A rest parameter (spread right): `..d`
309    Rest(&'a Ty),
310}
311
312impl fmt::Debug for TypeSigParam<'_> {
313    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
314        match self {
315            TypeSigParam::Pos(ty) => write!(f, "{ty:?}"),
316            TypeSigParam::Named(name, ty) => write!(f, "{name:?}: {ty:?}"),
317            // todo: the rest is not three dots
318            TypeSigParam::Rest(ty) => write!(f, "...: {ty:?}"),
319        }
320    }
321}
322
323/// The syntax source (definition) of a type node.
324/// todo: whether we should store them in the type node
325#[derive(Debug, Clone, PartialEq, Eq)]
326pub struct TypeSource {
327    /// A name node with span.
328    pub name_node: SyntaxNode,
329    /// A lazy evaluated name.
330    pub name_repr: OnceLock<StrRef>,
331    /// The attached documentation.
332    pub doc: StrRef,
333}
334
335impl Hash for TypeSource {
336    fn hash<H: Hasher>(&self, state: &mut H) {
337        self.name_node.hash(state);
338        self.doc.hash(state);
339    }
340}
341
342impl TypeSource {
343    /// Gets the name of the type node.
344    pub fn name(&self) -> StrRef {
345        self.name_repr
346            .get_or_init(|| {
347                let name = self.name_node.text();
348                if !name.is_empty() {
349                    return name.into();
350                }
351                let name = self.name_node.clone().into_text();
352                name.into()
353            })
354            .clone()
355    }
356}
357
358/// An ordered list of names.
359#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
360pub struct NameBone {
361    /// The names in the bone.
362    pub names: Box<[StrRef]>,
363}
364
365impl NameBone {
366    /// Creates an empty bone.
367    pub fn empty() -> Interned<Self> {
368        Interned::new(Self {
369            names: Box::new([]),
370        })
371    }
372}
373
374impl NameBone {
375    /// Finds the index of the name in the bone.
376    pub fn find(&self, name: &StrRef) -> Option<usize> {
377        self.names.binary_search_by(|probe| probe.cmp(name)).ok()
378    }
379}
380
381impl NameBone {
382    /// Intersects the names of two bones.
383    pub fn intersect_enumerate<'a>(
384        &'a self,
385        rhs: &'a NameBone,
386    ) -> impl Iterator<Item = (usize, usize)> + 'a {
387        let mut lhs_iter = self.names.iter().enumerate();
388        let mut rhs_iter = rhs.names.iter().enumerate();
389
390        let mut lhs = lhs_iter.next();
391        let mut rhs = rhs_iter.next();
392
393        std::iter::from_fn(move || {
394            'name_scanning: loop {
395                if let (Some((idx, lhs_key)), Some((j, rhs_key))) = (lhs, rhs) {
396                    match lhs_key.cmp(rhs_key) {
397                        std::cmp::Ordering::Less => {
398                            lhs = lhs_iter.next();
399                            continue 'name_scanning;
400                        }
401                        std::cmp::Ordering::Greater => {
402                            rhs = rhs_iter.next();
403                            continue 'name_scanning;
404                        }
405                        std::cmp::Ordering::Equal => {
406                            lhs = lhs_iter.next();
407                            rhs = rhs_iter.next();
408                            return Some((idx, j));
409                        }
410                    }
411                }
412                return None;
413            }
414        })
415    }
416}
417
418/// The state of a type variable (bounds of some type in program).
419#[derive(Clone, Default)]
420pub struct DynTypeBounds {
421    /// The lower bounds
422    pub lbs: rpds::HashTrieSetSync<Ty>,
423    /// The upper bounds
424    pub ubs: rpds::HashTrieSetSync<Ty>,
425}
426
427impl From<TypeBounds> for DynTypeBounds {
428    fn from(bounds: TypeBounds) -> Self {
429        Self {
430            lbs: bounds.lbs.into_iter().collect(),
431            ubs: bounds.ubs.into_iter().collect(),
432        }
433    }
434}
435
436impl DynTypeBounds {
437    /// Gets the frozen bounds.
438    pub fn freeze(&self) -> TypeBounds {
439        // sorted
440        let mut lbs: Vec<_> = self.lbs.iter().cloned().collect();
441        lbs.sort();
442        let mut ubs: Vec<_> = self.ubs.iter().cloned().collect();
443        ubs.sort();
444        TypeBounds { lbs, ubs }
445    }
446}
447
448/// A frozen type variable (bounds of some type in program).
449/// `t :> t1 | ... | tn <: f1 & ... & fn`
450/// `  lbs------------- ubs-------------`
451#[derive(Hash, Clone, PartialEq, Eq, Default, PartialOrd, Ord)]
452pub struct TypeBounds {
453    /// The lower bounds.
454    pub lbs: Vec<Ty>,
455    /// The upper bounds.
456    pub ubs: Vec<Ty>,
457}
458
459impl fmt::Debug for TypeBounds {
460    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
461        // write!(f, "{}", self.name)
462        // also where
463        if !self.lbs.is_empty() {
464            write!(f, " ⪰ {:?}", self.lbs[0])?;
465            for lb in &self.lbs[1..] {
466                write!(f, " | {lb:?}")?;
467            }
468        }
469        if !self.ubs.is_empty() {
470            write!(f, " ⪯ {:?}", self.ubs[0])?;
471            for ub in &self.ubs[1..] {
472                write!(f, " & {ub:?}")?;
473            }
474        }
475        Ok(())
476    }
477}
478
479/// A common type kinds for those types that has fields (abstracted record
480/// type).
481pub trait TypeInterface {
482    /// Gets the bone of a record.
483    /// See [`NameBone`] for more details.
484    fn bone(&self) -> &Interned<NameBone>;
485    /// Iterates over the fields of a record.
486    fn interface(&self) -> impl Iterator<Item = (&StrRef, &Ty)>;
487    /// Gets the field by bone offset.
488    fn field_by_bone_offset(&self, idx: usize) -> Option<&Ty>;
489    /// Gets the field by name.
490    fn field_by_name(&self, name: &StrRef) -> Option<&Ty> {
491        self.field_by_bone_offset(self.bone().find(name)?)
492    }
493}
494
495/// Extension common methods for [`TypeInterface`].
496pub trait TypeInterfaceExt: TypeInterface {
497    /// Convenience method to get the common fields of two records.
498    fn common_iface_fields<'a>(
499        &'a self,
500        rhs: &'a Self,
501    ) -> impl Iterator<Item = (&'a StrRef, &'a Ty, &'a Ty)> {
502        let lhs_names = self.bone();
503        let rhs_names = rhs.bone();
504
505        lhs_names
506            .intersect_enumerate(rhs_names)
507            .filter_map(move |(i, j)| {
508                let lhs = self.field_by_bone_offset(i)?;
509                let rhs = rhs.field_by_bone_offset(j)?;
510                Some((&lhs_names.names[i], lhs, rhs))
511            })
512    }
513}
514
515impl<T: TypeInterface> TypeInterfaceExt for T {}
516
517/// An instance of a typst type.
518#[derive(Debug, Hash, Clone, PartialEq)]
519pub struct InsTy {
520    /// The value of the instance.
521    pub val: Value,
522    /// The syntax source of the instance.
523    pub syntax: Option<Interned<TypeSource>>,
524}
525
526/// There are some case that val is not Eq, but we make it Eq for simplicity
527/// For example, a float instance which is NaN.
528impl Eq for InsTy {}
529
530/// Since we compare values by pointer ([`ptr_cmp`]), only interned instances
531/// are comparable.
532impl PartialOrd for Interned<InsTy> {
533    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
534        Some(self.cmp(other))
535    }
536}
537
538/// Since we compare values by pointer ([`ptr_cmp`]), only interned instances
539/// are comparable.
540impl Ord for Interned<InsTy> {
541    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
542        cmp_value(&self.val, &other.val)
543    }
544}
545
546fn cmp_value(x: &Value, y: &Value) -> std::cmp::Ordering {
547    match x.partial_cmp(y) {
548        Some(order) => return order,
549        None => {
550            let x_dis = val_discriminant(x);
551            let y_dis = val_discriminant(y);
552            if x_dis != y_dis {
553                return x_dis.cmp(&y_dis);
554            }
555        }
556    }
557
558    match (&x, &y) {
559        (Value::Str(x), Value::Str(y)) => x.cmp(y),
560        (Value::Bool(x), Value::Bool(y)) => x.cmp(y),
561        (Value::Int(x), Value::Int(y)) => x.cmp(y),
562        (Value::Decimal(x), Value::Decimal(y)) => x.cmp(y),
563        (Value::Angle(x), Value::Angle(y)) => x.cmp(y),
564        (Value::Ratio(x), Value::Ratio(y)) => x.cmp(y),
565        (Value::Fraction(x), Value::Fraction(y)) => x.cmp(y),
566        (Value::Version(x), Value::Version(y)) => x.cmp(y),
567        (Value::Bytes(x), Value::Bytes(y)) => x.cmp(y),
568        (Value::Duration(x), Value::Duration(y)) => x.cmp(y),
569        (Value::Type(x), Value::Type(y)) => x.cmp(y),
570        (Value::None, Value::None) | (Value::Auto, Value::Auto) => std::cmp::Ordering::Equal,
571        (Value::Array(x), Value::Array(y)) => cmp_by(x.iter(), y.iter(), cmp_value),
572        (Value::Dict(x), Value::Dict(y)) => cmp_by(x.iter(), y.iter(), |(xk, xv), (yk, yv)| {
573            xk.cmp(yk).then_with(|| cmp_value(xv, yv))
574        }),
575        (Value::Label(x), Value::Label(y)) => x.resolve().cmp(&y.resolve()),
576        (Value::Float(x), Value::Float(y)) => x.to_bits().cmp(&y.to_bits()),
577        (Value::Length(x), Value::Length(y)) => x.abs.cmp(&y.abs).then_with(|| x.em.cmp(&y.em)),
578        (Value::Relative(x), Value::Relative(y)) => x.rel.cmp(&y.rel).then_with(|| {
579            x.abs
580                .abs
581                .cmp(&y.abs.abs)
582                .then_with(|| x.abs.em.cmp(&y.abs.em))
583        }),
584        (Value::Func(x), Value::Func(y)) => {
585            if !x.span().is_detached() && !y.span().is_detached() {
586                return x.span().into_raw().cmp(&y.span().into_raw());
587            }
588
589            use typst::foundations::func::Repr;
590            match (x.inner(), y.inner()) {
591                (Repr::Element(x), Repr::Element(y)) => x.cmp(y),
592                _ => ptr_cmp(x, y),
593            }
594        }
595        (Value::Args(x), Value::Args(y)) => {
596            if !x.span.is_detached() && !y.span.is_detached() {
597                return x.span.into_raw().cmp(&y.span.into_raw());
598            }
599
600            ptr_cmp(x, y)
601        }
602        (Value::Module(x), Value::Module(y)) => match (x.file_id(), y.file_id()) {
603            (Some(x), Some(y)) => x.cmp(&y),
604            (Some(..), None) => std::cmp::Ordering::Less,
605            (None, Some(..)) => std::cmp::Ordering::Greater,
606            (None, None) => ptr_cmp(x, y),
607        },
608        (Value::Datetime(x), Value::Datetime(y)) => {
609            x.partial_cmp(y).unwrap_or_else(|| ptr_cmp(x, y))
610        }
611        (Value::Color(x), Value::Color(y)) => ptr_cmp(x, y),
612        (Value::Gradient(x), Value::Gradient(y)) => ptr_cmp(x, y),
613        (Value::Tiling(x), Value::Tiling(y)) => ptr_cmp(x, y),
614        (Value::Symbol(x), Value::Symbol(y)) => ptr_cmp(x, y),
615        (Value::Content(x), Value::Content(y)) => ptr_cmp(x, y),
616        (Value::Styles(x), Value::Styles(y)) => ptr_cmp(x, y),
617        (Value::Dyn(x), Value::Dyn(y)) => ptr_cmp(x, y),
618        _ => ptr_cmp(x, y),
619    }
620}
621
622fn cmp_by<T>(
623    mut x_iter: impl Iterator<Item = T>,
624    mut y_iter: impl Iterator<Item = T>,
625    mut cmp: impl FnMut(T, T) -> std::cmp::Ordering,
626) -> std::cmp::Ordering {
627    use std::cmp::Ordering;
628    loop {
629        match (x_iter.next(), y_iter.next()) {
630            (Some(x_item), Some(y_item)) => match cmp(x_item, y_item) {
631                Ordering::Equal => continue,
632                other => return other,
633            },
634            (Some(_), None) => return Ordering::Greater,
635            (None, Some(_)) => return Ordering::Less,
636            (None, None) => return Ordering::Equal,
637        }
638    }
639}
640
641fn val_discriminant(val: &Value) -> TypstValueEnum {
642    match val {
643        Value::Str(..) => TypstValueEnum::Str,
644        Value::None => TypstValueEnum::None,
645        Value::Auto => TypstValueEnum::Auto,
646        Value::Array(..) => TypstValueEnum::Array,
647        Value::Args(..) => TypstValueEnum::Args,
648        Value::Dict(..) => TypstValueEnum::Dict,
649        Value::Module(..) => TypstValueEnum::Module,
650        Value::Func(..) => TypstValueEnum::Func,
651        Value::Label(..) => TypstValueEnum::Label,
652        Value::Bool(..) => TypstValueEnum::Bool,
653        Value::Int(..) => TypstValueEnum::Int,
654        Value::Float(..) => TypstValueEnum::Float,
655        Value::Decimal(..) => TypstValueEnum::Decimal,
656        Value::Length(..) => TypstValueEnum::Length,
657        Value::Angle(..) => TypstValueEnum::Angle,
658        Value::Ratio(..) => TypstValueEnum::Ratio,
659        Value::Relative(..) => TypstValueEnum::Relative,
660        Value::Fraction(..) => TypstValueEnum::Fraction,
661        Value::Color(..) => TypstValueEnum::Color,
662        Value::Gradient(..) => TypstValueEnum::Gradient,
663        Value::Tiling(..) => TypstValueEnum::Tiling,
664        Value::Symbol(..) => TypstValueEnum::Symbol,
665        Value::Version(..) => TypstValueEnum::Version,
666        Value::Bytes(..) => TypstValueEnum::Bytes,
667        Value::Datetime(..) => TypstValueEnum::Datetime,
668        Value::Duration(..) => TypstValueEnum::Duration,
669        Value::Content(..) => TypstValueEnum::Content,
670        Value::Styles(..) => TypstValueEnum::Styles,
671        Value::Type(..) => TypstValueEnum::Type,
672        Value::Dyn(..) => TypstValueEnum::Dyn,
673    }
674}
675
676fn ptr_cmp<T: PartialEq>(x: &T, y: &T) -> std::cmp::Ordering {
677    if x == y {
678        std::cmp::Ordering::Equal
679    } else {
680        let x = std::ptr::from_ref(x);
681        let y = std::ptr::from_ref(y);
682        x.cmp(&y)
683    }
684}
685
686#[derive(PartialEq, Eq, PartialOrd, Ord)]
687enum TypstValueEnum {
688    Str,
689    None,
690    Auto,
691    Array,
692    Args,
693    Dict,
694    Module,
695    Func,
696    Label,
697    Bool,
698    Int,
699    Float,
700    Decimal,
701    Length,
702    Angle,
703    Ratio,
704    Relative,
705    Fraction,
706    Color,
707    Gradient,
708    Tiling,
709    Symbol,
710    Version,
711    Bytes,
712    Datetime,
713    Duration,
714    Content,
715    Styles,
716    Type,
717    Dyn,
718}
719
720impl InsTy {
721    /// Creates an instance.
722    pub fn new(val: Value) -> Interned<Self> {
723        Self { val, syntax: None }.into()
724    }
725
726    /// Creates an instance with a sapn.
727    pub fn new_at(val: Value, span: Span) -> Interned<Self> {
728        let mut name = SyntaxNode::leaf(SyntaxKind::Ident, "");
729        name.synthesize(span);
730        Interned::new(Self {
731            val,
732            syntax: Some(Interned::new(TypeSource {
733                name_node: name,
734                name_repr: OnceLock::new(),
735                doc: "".into(),
736            })),
737        })
738    }
739
740    /// Creates an instance with a documentation string.
741    pub fn new_doc(val: Value, doc: impl Into<StrRef>) -> Interned<Self> {
742        Interned::new(Self {
743            val,
744            syntax: Some(Interned::new(TypeSource {
745                name_node: SyntaxNode::default(),
746                name_repr: OnceLock::new(),
747                doc: doc.into(),
748            })),
749        })
750    }
751
752    /// Gets the span of the instance.
753    pub fn span(&self) -> Span {
754        self.syntax
755            .as_ref()
756            .map(|source| source.name_node.span())
757            .or_else(|| {
758                Some(match &self.val {
759                    Value::Func(func) => func.span(),
760                    Value::Args(args) => args.span,
761                    Value::Content(content) => content.span(),
762                    _ => return None,
763                })
764            })
765            .unwrap_or_else(Span::detached)
766    }
767}
768
769/// Describes a function parameter attribute.
770#[derive(
771    Debug, Clone, Copy, Hash, Serialize, Deserialize, Default, PartialEq, Eq, PartialOrd, Ord,
772)]
773pub struct ParamAttrs {
774    /// Whether the parameter is positional.
775    pub positional: bool,
776    /// Whether the parameter is named.
777    ///
778    /// Can be true even if `positional` is true if the parameter can be given
779    /// in both variants.
780    pub named: bool,
781    /// Whether the parameter can be given any number of times.
782    pub variadic: bool,
783    /// Whether the parameter is settable with a set rule.
784    pub settable: bool,
785}
786
787impl ParamAttrs {
788    /// Creates a positional parameter attribute.
789    pub fn positional() -> ParamAttrs {
790        ParamAttrs {
791            positional: true,
792            named: false,
793            variadic: false,
794            settable: false,
795        }
796    }
797
798    /// Creates a named parameter attribute.
799    pub fn named() -> ParamAttrs {
800        ParamAttrs {
801            positional: false,
802            named: true,
803            variadic: false,
804            settable: false,
805        }
806    }
807
808    /// Creates a variadic parameter attribute.
809    pub fn variadic() -> ParamAttrs {
810        ParamAttrs {
811            positional: true,
812            named: false,
813            variadic: true,
814            settable: false,
815        }
816    }
817}
818
819impl From<&ParamInfo> for ParamAttrs {
820    fn from(param: &ParamInfo) -> Self {
821        ParamAttrs {
822            positional: param.positional,
823            named: param.named,
824            variadic: param.variadic,
825            settable: param.settable,
826        }
827    }
828}
829
830/// Describes a parameter type.
831#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
832pub struct ParamTy {
833    /// The name of the parameter.
834    pub name: StrRef,
835    /// The docstring of the parameter.
836    pub docs: Option<EcoString>,
837    /// The default value of the variable.
838    pub default: Option<EcoString>,
839    /// The type of the parameter.
840    pub ty: Ty,
841    /// The attributes of the parameter.
842    pub attrs: ParamAttrs,
843}
844
845impl ParamTy {
846    /// Creates an untyped field type.
847    pub fn new_untyped(name: StrRef, attrs: ParamAttrs) -> Interned<Self> {
848        Self::new(Ty::Any, name, attrs)
849    }
850
851    /// Creates a typed field type.
852    pub fn new(ty: Ty, name: StrRef, attrs: ParamAttrs) -> Interned<Self> {
853        Interned::new(Self {
854            name,
855            ty,
856            docs: None,
857            default: None,
858            attrs,
859        })
860    }
861}
862
863/// A type variable.
864#[derive(Hash, Clone, PartialEq, Eq)]
865pub struct TypeVar {
866    /// The name of the type variable.
867    pub name: StrRef,
868    /// The definition id of the type variable.
869    pub def: DeclExpr,
870}
871
872impl Ord for TypeVar {
873    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
874        // todo: buggy
875        self.def.cmp(&other.def)
876    }
877}
878
879impl TypeVar {
880    /// Low-performance comparison but it is free from the concurrency issue.
881    /// This is only used for making stable test snapshots.
882    pub fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
883        self.def.strict_cmp(&other.def)
884    }
885}
886
887impl PartialOrd for TypeVar {
888    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
889        Some(self.cmp(other))
890    }
891}
892
893impl fmt::Debug for TypeVar {
894    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
895        write!(f, "@{}", self.name)
896    }
897}
898
899impl TypeVar {
900    /// Creates a type variable.
901    pub fn new(name: StrRef, def: DeclExpr) -> Interned<Self> {
902        Interned::new(Self { name, def })
903    }
904
905    /// Gets the name of the type variable.
906    pub fn name(&self) -> StrRef {
907        self.name.clone()
908    }
909}
910
911/// A record type.
912#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
913pub struct RecordTy {
914    /// The names of the fields.
915    pub names: Interned<NameBone>,
916    /// The types of the fields.
917    pub types: Interned<Vec<Ty>>,
918}
919
920impl RecordTy {
921    /// Shapes the fields of a record.
922    pub fn shape_fields(mut fields: Vec<(StrRef, Ty)>) -> (NameBone, Vec<Ty>) {
923        fields.sort_by(|a, b| a.0.cmp(&b.0));
924        let names = NameBone {
925            names: fields.iter().map(|(name, _)| name.clone()).collect(),
926        };
927        let types = fields.into_iter().map(|(_, ty)| ty).collect::<Vec<_>>();
928
929        (names, types)
930    }
931
932    /// Creates a record type.
933    pub fn new(fields: Vec<(StrRef, Ty)>) -> Interned<Self> {
934        let (names, types) = Self::shape_fields(fields);
935        Interned::new(Self {
936            types: Interned::new(types),
937            names: Interned::new(names),
938        })
939    }
940}
941
942impl TypeInterface for RecordTy {
943    fn bone(&self) -> &Interned<NameBone> {
944        &self.names
945    }
946
947    fn field_by_bone_offset(&self, idx: usize) -> Option<&Ty> {
948        self.types.get(idx)
949    }
950
951    fn interface(&self) -> impl Iterator<Item = (&StrRef, &Ty)> {
952        self.names.names.iter().zip(self.types.iter())
953    }
954}
955
956impl fmt::Debug for RecordTy {
957    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
958        f.write_str("{")?;
959        interpersed(
960            f,
961            self.interface()
962                .map(|(name, ty)| TypeSigParam::Named(name, ty)),
963        )?;
964        f.write_str("}")
965    }
966}
967
968/// A typst function type.
969#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
970pub struct SigTy {
971    /// The input types of the function.
972    pub inputs: Interned<Vec<Ty>>,
973    /// The return (body) type of the function.
974    pub body: Option<Ty>,
975    /// The name bone of the named parameters.
976    pub names: Interned<NameBone>,
977    /// The index of the first named parameter.
978    pub name_started: u32,
979    /// Whether the function has a spread left parameter.
980    pub spread_left: bool,
981    /// Whether the function has a spread right parameter.
982    pub spread_right: bool,
983}
984
985impl SigTy {
986    /// Creates an function that accepts any arguments: `(a, b: c, ..d)`
987    pub fn any() -> Interned<SigTy> {
988        let rest = Ty::Array(Interned::new(Ty::Any));
989        Interned::new(Self {
990            inputs: Interned::new(vec![rest]),
991            body: Some(Ty::Any),
992            names: NameBone::empty(),
993            name_started: 0,
994            spread_left: false,
995            spread_right: true,
996        })
997    }
998
999    /// Creates an array constructor: `(a)`
1000    #[comemo::memoize]
1001    pub fn array_cons(elem: Ty, anyify: bool) -> Interned<SigTy> {
1002        let rest = Ty::Array(Interned::new(elem.clone()));
1003        let ret = if anyify { Ty::Any } else { rest.clone() };
1004        Interned::new(Self {
1005            inputs: Interned::new(vec![rest]),
1006            body: Some(ret),
1007            names: NameBone::empty(),
1008            name_started: 0,
1009            spread_left: false,
1010            spread_right: true,
1011        })
1012    }
1013
1014    /// Creates a unary constructor: `(a) => b`
1015    #[comemo::memoize]
1016    pub fn unary(inp: Ty, ret: Ty) -> Interned<SigTy> {
1017        Interned::new(Self {
1018            inputs: Interned::new(vec![inp]),
1019            body: Some(ret),
1020            names: NameBone::empty(),
1021            name_started: 1,
1022            spread_left: false,
1023            spread_right: false,
1024        })
1025    }
1026
1027    /// Creates a tuple constructor: `(a, b, c)`
1028    #[comemo::memoize]
1029    pub fn tuple_cons(elems: Interned<Vec<Ty>>, anyify: bool) -> Interned<SigTy> {
1030        let ret = if anyify {
1031            Ty::Any
1032        } else {
1033            Ty::Tuple(elems.clone())
1034        };
1035        let name_started = elems.len() as u32;
1036        Interned::new(Self {
1037            inputs: elems,
1038            body: Some(ret),
1039            names: NameBone::empty(),
1040            name_started,
1041            spread_left: false,
1042            spread_right: false,
1043        })
1044    }
1045
1046    /// Creates a dictionary constructor: `(a: b, c: d)`
1047    #[comemo::memoize]
1048    pub fn dict_cons(named: &Interned<RecordTy>, anyify: bool) -> Interned<SigTy> {
1049        let ret = if anyify {
1050            Ty::Any
1051        } else {
1052            Ty::Dict(named.clone())
1053        };
1054
1055        Interned::new(Self {
1056            inputs: named.types.clone(),
1057            body: Some(ret),
1058            names: named.names.clone(),
1059            name_started: 0,
1060            spread_left: false,
1061            spread_right: false,
1062        })
1063    }
1064
1065    /// Sets the return type of the function.
1066    pub fn with_body(mut self, res_ty: Ty) -> Self {
1067        self.body = Some(res_ty);
1068        self
1069    }
1070
1071    /// Creates a function type.
1072    pub fn new(
1073        pos: impl ExactSizeIterator<Item = Ty>,
1074        named: impl IntoIterator<Item = (StrRef, Ty)>,
1075        rest_left: Option<Ty>,
1076        rest_right: Option<Ty>,
1077        ret_ty: Option<Ty>,
1078    ) -> Self {
1079        let named = named.into_iter().collect::<Vec<_>>();
1080        let (names, mut named_types) = RecordTy::shape_fields(named);
1081        let spread_left = rest_left.is_some();
1082        let spread_right = rest_right.is_some();
1083
1084        let name_started = if spread_right { 1 } else { 0 } + named_types.len();
1085        let mut types = Vec::with_capacity(
1086            pos.len() + named_types.len() + spread_left as usize + spread_right as usize,
1087        );
1088        types.extend(pos);
1089        types.append(&mut named_types);
1090        types.extend(rest_left);
1091        types.extend(rest_right);
1092
1093        let name_started = (types.len() - name_started) as u32;
1094
1095        Self {
1096            inputs: Interned::new(types),
1097            body: ret_ty,
1098            names: Interned::new(names),
1099            name_started,
1100            spread_left,
1101            spread_right,
1102        }
1103    }
1104}
1105
1106impl Default for SigTy {
1107    fn default() -> Self {
1108        Self {
1109            inputs: Interned::new(Vec::new()),
1110            body: None,
1111            names: NameBone::empty(),
1112            name_started: 0,
1113            spread_left: false,
1114            spread_right: false,
1115        }
1116    }
1117}
1118
1119impl TypeInterface for SigTy {
1120    fn bone(&self) -> &Interned<NameBone> {
1121        &self.names
1122    }
1123
1124    fn interface(&self) -> impl Iterator<Item = (&StrRef, &Ty)> {
1125        let names = self.names.names.iter();
1126        let types = self.inputs.iter().skip(self.name_started as usize);
1127        names.zip(types)
1128    }
1129
1130    fn field_by_bone_offset(&self, offset: usize) -> Option<&Ty> {
1131        self.inputs.get(offset + self.name_started as usize)
1132    }
1133}
1134
1135impl SigTy {
1136    /// Gets the input types of the function.
1137    pub fn inputs(&self) -> impl Iterator<Item = &Ty> {
1138        self.inputs.iter()
1139    }
1140
1141    /// Gets the positional parameters of the function.
1142    pub fn positional_params(&self) -> impl ExactSizeIterator<Item = &Ty> {
1143        self.inputs.iter().take(self.name_started as usize)
1144    }
1145
1146    /// Gets the parameter at the given index.
1147    pub fn pos(&self, idx: usize) -> Option<&Ty> {
1148        (idx < self.name_started as usize)
1149            .then_some(())
1150            .and_then(|_| self.inputs.get(idx))
1151    }
1152
1153    /// Gets the parameter or the rest parameter at the given index.
1154    pub fn pos_or_rest(&self, idx: usize) -> Option<Ty> {
1155        let nth = self.pos(idx).cloned();
1156        nth.or_else(|| {
1157            let rest_idx = || idx.saturating_sub(self.positional_params().len());
1158
1159            let rest_ty = self.rest_param()?;
1160            match rest_ty {
1161                Ty::Array(ty) => Some(ty.as_ref().clone()),
1162                Ty::Tuple(tys) => tys.get(rest_idx()).cloned(),
1163                _ => None,
1164            }
1165        })
1166    }
1167
1168    /// Gets the named parameters of the function.
1169    pub fn named_params(&self) -> impl ExactSizeIterator<Item = (&StrRef, &Ty)> {
1170        let named_names = self.names.names.iter();
1171        let named_types = self.inputs.iter().skip(self.name_started as usize);
1172
1173        named_names.zip(named_types)
1174    }
1175
1176    /// Gets the named parameter by given name.
1177    pub fn named(&self, name: &StrRef) -> Option<&Ty> {
1178        let idx = self.names.find(name)?;
1179        self.inputs.get(idx + self.name_started as usize)
1180    }
1181
1182    /// Gets the rest parameter of the function.
1183    pub fn rest_param(&self) -> Option<&Ty> {
1184        if self.spread_right {
1185            self.inputs.last()
1186        } else {
1187            None
1188        }
1189    }
1190
1191    /// Matches the function type with the given arguments.
1192    pub fn matches<'a>(
1193        &'a self,
1194        args: &'a SigTy,
1195        with: Option<&'a Vec<Interned<SigTy>>>,
1196    ) -> impl Iterator<Item = (&'a Ty, &'a Ty)> + 'a {
1197        let with_len = with
1198            .map(|w| w.iter().map(|w| w.positional_params().len()).sum::<usize>())
1199            .unwrap_or(0);
1200
1201        let sig_pos = self.positional_params();
1202        let arg_pos = args.positional_params();
1203
1204        let sig_rest = self.rest_param();
1205        let arg_rest = args.rest_param();
1206
1207        let max_len = sig_pos.len().max(with_len + arg_pos.len())
1208            + if sig_rest.is_some() && arg_rest.is_some() {
1209                1
1210            } else {
1211                0
1212            };
1213
1214        let arg_pos = with
1215            .into_iter()
1216            .flat_map(|w| w.iter().rev().map(|w| w.positional_params()))
1217            .flatten()
1218            .chain(arg_pos);
1219
1220        let sig_stream = sig_pos.chain(sig_rest.into_iter().cycle()).take(max_len);
1221        let arg_stream = arg_pos.chain(arg_rest.into_iter().cycle()).take(max_len);
1222
1223        let pos = sig_stream.zip(arg_stream);
1224        let common_ifaces = with
1225            .map(|args_all| args_all.iter().rev())
1226            .into_iter()
1227            .flatten()
1228            .flat_map(|args| self.common_iface_fields(args))
1229            .chain(self.common_iface_fields(args));
1230        let named = common_ifaces.map(|(_, l, r)| (l, r));
1231
1232        pos.chain(named)
1233    }
1234}
1235
1236impl fmt::Debug for SigTy {
1237    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1238        f.write_str("(")?;
1239        let pos = self.positional_params().map(TypeSigParam::Pos);
1240        let named = self
1241            .named_params()
1242            .map(|(name, ty)| TypeSigParam::Named(name, ty));
1243        let rest = self.rest_param().map(TypeSigParam::Rest);
1244        interpersed(f, pos.chain(named).chain(rest))?;
1245        f.write_str(") => ")?;
1246        if let Some(ret) = &self.body {
1247            ret.fmt(f)?;
1248        } else {
1249            f.write_str("any")?;
1250        }
1251        Ok(())
1252    }
1253}
1254
1255/// A function argument type.
1256pub type ArgsTy = SigTy;
1257
1258/// A pattern type.
1259pub type PatternTy = SigTy;
1260
1261/// A type with partially applied arguments.
1262#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
1263pub struct SigWithTy {
1264    /// The signature of the function.
1265    pub sig: TyRef,
1266    /// The arguments applied to the function.
1267    pub with: Interned<ArgsTy>,
1268}
1269
1270impl SigWithTy {
1271    /// Creates a type with applied arguments.
1272    pub fn new(sig: TyRef, with: Interned<ArgsTy>) -> Interned<Self> {
1273        Interned::new(Self { sig, with })
1274    }
1275}
1276
1277impl fmt::Debug for SigWithTy {
1278    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1279        write!(f, "{:?}.with({:?})", self.sig, self.with)
1280    }
1281}
1282
1283/// A field selection type.
1284#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
1285pub struct SelectTy {
1286    /// The type to select from.
1287    pub ty: TyRef,
1288    /// The field to select
1289    pub select: StrRef,
1290}
1291
1292impl SelectTy {
1293    /// Creates a field selection type.
1294    pub fn new(ty: TyRef, select: StrRef) -> Interned<Self> {
1295        Interned::new(Self { ty, select })
1296    }
1297}
1298
1299impl fmt::Debug for SelectTy {
1300    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1301        write!(f, "{:?}.{}", RefDebug(&self.ty), self.select)
1302    }
1303}
1304
1305/// A unary operation type.
1306#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1307pub struct TypeUnary {
1308    /// The operand of the unary operation.
1309    pub lhs: Ty,
1310    /// The kind of the unary operation
1311    pub op: UnaryOp,
1312}
1313
1314impl PartialOrd for TypeUnary {
1315    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1316        Some(self.cmp(other))
1317    }
1318}
1319
1320impl Ord for TypeUnary {
1321    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1322        let op_as_int = self.op as u8;
1323        let other_op_as_int = other.op as u8;
1324        op_as_int
1325            .cmp(&other_op_as_int)
1326            .then_with(|| self.lhs.cmp(&other.lhs))
1327    }
1328}
1329
1330impl TypeUnary {
1331    /// Creates a unary operation type.
1332    pub fn new(op: UnaryOp, lhs: Ty) -> Interned<Self> {
1333        Interned::new(Self { lhs, op })
1334    }
1335
1336    /// Gets the operands of the unary operation.
1337    pub fn operands(&self) -> [&Ty; 1] {
1338        [&self.lhs]
1339    }
1340}
1341
1342/// The kind of binary operation.
1343pub type BinaryOp = ast::BinOp;
1344
1345/// A binary operation type.
1346#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1347pub struct TypeBinary {
1348    /// The operands of the binary operation.
1349    pub operands: (Ty, Ty),
1350    /// The kind of the binary operation.
1351    pub op: BinaryOp,
1352}
1353
1354impl PartialOrd for TypeBinary {
1355    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1356        Some(self.cmp(other))
1357    }
1358}
1359
1360impl Ord for TypeBinary {
1361    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1362        let op_as_int = self.op as u8;
1363        let other_op_as_int = other.op as u8;
1364        op_as_int
1365            .cmp(&other_op_as_int)
1366            .then_with(|| self.operands.cmp(&other.operands))
1367    }
1368}
1369
1370impl TypeBinary {
1371    /// Creates a binary operation type.
1372    pub fn new(op: BinaryOp, lhs: Ty, rhs: Ty) -> Interned<Self> {
1373        Interned::new(Self {
1374            operands: (lhs, rhs),
1375            op,
1376        })
1377    }
1378
1379    /// Gets the operands of the binary operation.
1380    pub fn operands(&self) -> [&Ty; 2] {
1381        [&self.operands.0, &self.operands.1]
1382    }
1383}
1384
1385/// A conditional type.
1386/// `if t1 then t2 else t3`
1387#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
1388pub struct IfTy {
1389    /// The condition.
1390    pub cond: TyRef,
1391    /// The type when the condition is true.
1392    pub then: TyRef,
1393    /// The type when the condition is false.
1394    pub else_: TyRef,
1395}
1396
1397impl IfTy {
1398    /// Creates a conditional type.
1399    pub fn new(cond: TyRef, then: TyRef, else_: TyRef) -> Interned<Self> {
1400        Interned::new(Self { cond, then, else_ })
1401    }
1402}
1403
1404/// The type information on a group of syntax structures (typing).
1405#[derive(Default)]
1406pub struct TypeInfo {
1407    /// Whether the typing is valid.
1408    pub valid: bool,
1409    /// The belonging file id.
1410    pub fid: Option<FileId>,
1411    /// The used revision.
1412    pub revision: usize,
1413    /// The exported types.
1414    pub exports: FxHashMap<StrRef, Ty>,
1415    /// The typing on definitions.
1416    pub vars: FxHashMap<DeclExpr, TypeVarBounds>,
1417    /// The checked documentation of definitions.
1418    pub var_docs: FxHashMap<DeclExpr, Arc<UntypedDefDocs>>,
1419    /// The local binding of the type variable.
1420    pub local_binds: snapshot_map::SnapshotMap<DeclExpr, Ty>,
1421    /// The typing on syntax structures.
1422    pub mapping: FxHashMap<Span, FxHashSet<Ty>>,
1423    /// The cache to canonicalize types.
1424    pub(super) cano_cache: Mutex<TypeCanoStore>,
1425}
1426
1427impl Hash for TypeInfo {
1428    fn hash<H: Hasher>(&self, state: &mut H) {
1429        self.valid.hash(state);
1430        self.fid.hash(state);
1431        self.revision.hash(state);
1432    }
1433}
1434
1435impl TyCtx for TypeInfo {
1436    fn global_bounds(&self, var: &Interned<TypeVar>, _pol: bool) -> Option<DynTypeBounds> {
1437        let v = self.vars.get(&var.def)?;
1438        Some(v.bounds.bounds().read().clone())
1439    }
1440
1441    fn local_bind_of(&self, var: &Interned<TypeVar>) -> Option<Ty> {
1442        self.local_binds.get(&var.def).cloned()
1443    }
1444}
1445
1446impl TypeInfo {
1447    /// Gets the type of a syntax structure.
1448    pub fn type_of_span(&self, site: Span) -> Option<Ty> {
1449        self.mapping
1450            .get(&site)
1451            .cloned()
1452            .map(|types| Ty::from_types(types.into_iter()))
1453    }
1454
1455    // todo: distinguish at least, at most
1456    /// Witnesses a lower-bound type on a syntax structure.
1457    pub fn witness_at_least(&mut self, site: Span, ty: Ty) {
1458        Self::witness_(site, ty, &mut self.mapping);
1459    }
1460    /// Witnesses a upper-bound type on a syntax structure.
1461    pub fn witness_at_most(&mut self, site: Span, ty: Ty) {
1462        Self::witness_(site, ty, &mut self.mapping);
1463    }
1464
1465    /// Witnesses a type.
1466    pub fn witness_(site: Span, ty: Ty, mapping: &mut FxHashMap<Span, FxHashSet<Ty>>) {
1467        if site.is_detached() {
1468            return;
1469        }
1470
1471        // todo: intersect/union
1472        mapping.entry(site).or_default().insert(ty);
1473    }
1474
1475    /// Converts a type to a type with bounds.
1476    pub fn to_bounds(&self, def: Ty) -> DynTypeBounds {
1477        let mut store = DynTypeBounds::default();
1478        match def {
1479            Ty::Var(v) => {
1480                let w = self.vars.get(&v.def).unwrap();
1481                match &w.bounds {
1482                    FlowVarKind::Strong(bounds) | FlowVarKind::Weak(bounds) => {
1483                        let w = bounds.read();
1484                        for bound in w.lbs.iter() {
1485                            store.lbs.insert_mut(bound.clone());
1486                        }
1487                        for bound in w.ubs.iter() {
1488                            store.ubs.insert_mut(bound.clone());
1489                        }
1490                    }
1491                }
1492            }
1493            Ty::Let(bounds) => {
1494                for bound in bounds.lbs.iter() {
1495                    store.lbs.insert_mut(bound.clone());
1496                }
1497                for bound in bounds.ubs.iter() {
1498                    store.ubs.insert_mut(bound.clone());
1499                }
1500            }
1501            _ => {
1502                store.ubs.insert_mut(def);
1503            }
1504        }
1505
1506        store
1507    }
1508}
1509
1510impl TyCtxMut for TypeInfo {
1511    type Snap = ena::undo_log::Snapshot;
1512
1513    fn start_scope(&mut self) -> Self::Snap {
1514        self.local_binds.snapshot()
1515    }
1516
1517    fn end_scope(&mut self, snap: Self::Snap) {
1518        self.local_binds.rollback_to(snap);
1519    }
1520
1521    fn bind_local(&mut self, var: &Interned<TypeVar>, ty: Ty) {
1522        self.local_binds.insert(var.def.clone(), ty);
1523    }
1524
1525    fn type_of_func(&mut self, _func: &typst::foundations::Func) -> Option<Interned<SigTy>> {
1526        None
1527    }
1528
1529    fn type_of_value(&mut self, _val: &Value) -> Ty {
1530        Ty::Any
1531    }
1532
1533    fn check_module_item(&mut self, _module: FileId, _key: &StrRef) -> Option<Ty> {
1534        None
1535    }
1536}
1537
1538/// A type variable bounds.
1539#[derive(Clone)]
1540pub struct TypeVarBounds {
1541    /// The type variable representation.
1542    pub var: Interned<TypeVar>,
1543    /// The bounds of the type variable.
1544    pub bounds: FlowVarKind,
1545}
1546
1547impl fmt::Debug for TypeVarBounds {
1548    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1549        write!(f, "{:?}", self.var)
1550    }
1551}
1552
1553impl TypeVarBounds {
1554    /// Creates a type variable bounds.
1555    pub fn new(var: TypeVar, init: DynTypeBounds) -> Self {
1556        Self {
1557            var: Interned::new(var),
1558            bounds: FlowVarKind::Strong(Arc::new(RwLock::new(init.clone()))),
1559        }
1560    }
1561
1562    /// Gets the name of the type variable.
1563    pub fn name(&self) -> &StrRef {
1564        &self.var.name
1565    }
1566
1567    /// Gets self as a type.
1568    pub fn as_type(&self) -> Ty {
1569        Ty::Var(self.var.clone())
1570    }
1571
1572    /// Slightly closes the type variable.
1573    pub fn weaken(&mut self) {
1574        match &self.bounds {
1575            FlowVarKind::Strong(w) => {
1576                self.bounds = FlowVarKind::Weak(w.clone());
1577            }
1578            FlowVarKind::Weak(_) => {}
1579        }
1580    }
1581}
1582
1583/// A type variable bounds.
1584#[derive(Clone)]
1585pub enum FlowVarKind {
1586    /// A type variable that receives both types and values (type instances).
1587    Strong(Arc<RwLock<DynTypeBounds>>),
1588    /// A type variable that receives only types.
1589    /// The received values will be lifted to types.
1590    Weak(Arc<RwLock<DynTypeBounds>>),
1591}
1592
1593impl FlowVarKind {
1594    /// Gets the bounds of the type variable.
1595    pub fn bounds(&self) -> &RwLock<DynTypeBounds> {
1596        match self {
1597            FlowVarKind::Strong(w) | FlowVarKind::Weak(w) => w,
1598        }
1599    }
1600}
1601
1602/// A cache to canonicalize types.
1603#[derive(Default)]
1604pub(super) struct TypeCanoStore {
1605    /// Maps a type to its canonical form.
1606    pub cano_cache: FxHashMap<(Ty, bool), Ty>,
1607    /// Maps a local type to its canonical form.
1608    pub cano_local_cache: FxHashMap<(DeclExpr, bool), Ty>,
1609    /// The negative bounds of a type variable.
1610    pub negatives: FxHashSet<DeclExpr>,
1611    /// The positive bounds of a type variable.
1612    pub positives: FxHashSet<DeclExpr>,
1613}
1614
1615impl_internable!(Ty,);
1616impl_internable!(InsTy,);
1617impl_internable!(ParamTy,);
1618impl_internable!(TypeSource,);
1619impl_internable!(TypeVar,);
1620impl_internable!(SigWithTy,);
1621impl_internable!(SigTy,);
1622impl_internable!(RecordTy,);
1623impl_internable!(SelectTy,);
1624impl_internable!(TypeUnary,);
1625impl_internable!(TypeBinary,);
1626impl_internable!(IfTy,);
1627impl_internable!(Vec<Ty>,);
1628impl_internable!(TypeBounds,);
1629impl_internable!(NameBone,);
1630impl_internable!(PackageId,);
1631impl_internable!((Ty, Ty),);
1632
1633struct RefDebug<'a>(&'a Ty);
1634
1635impl fmt::Debug for RefDebug<'_> {
1636    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1637        match self.0 {
1638            Ty::Var(v) => write!(f, "@v{:?}", v.name()),
1639            _ => write!(f, "{:?}", self.0),
1640        }
1641    }
1642}
1643
1644fn interpersed<T: fmt::Debug>(
1645    f: &mut fmt::Formatter<'_>,
1646    iter: impl Iterator<Item = T>,
1647) -> fmt::Result {
1648    let mut first = true;
1649    for arg in iter {
1650        if first {
1651            first = false;
1652        } else {
1653            f.write_str(", ")?;
1654        }
1655        arg.fmt(f)?;
1656    }
1657    Ok(())
1658}
1659
1660#[cfg(test)]
1661mod tests {
1662    use insta::{assert_debug_snapshot, assert_snapshot};
1663
1664    use crate::ty::tests::*;
1665
1666    #[test]
1667    fn test_ty_size() {
1668        use super::*;
1669        assert!(size_of::<Ty>() <= size_of::<usize>() * 2);
1670    }
1671
1672    #[test]
1673    fn test_ty() {
1674        use super::*;
1675        let ty = Ty::Builtin(BuiltinTy::Clause);
1676        let ty_ref = TyRef::new(ty.clone());
1677        assert_debug_snapshot!(ty_ref, @"Clause");
1678    }
1679
1680    #[test]
1681    fn test_sig_matches() {
1682        use super::*;
1683
1684        fn matches(
1685            sig: Interned<SigTy>,
1686            args: Interned<SigTy>,
1687            with: Option<Vec<Interned<ArgsTy>>>,
1688        ) -> String {
1689            let res = sig.matches(&args, with.as_ref()).collect::<Vec<_>>();
1690            format!("{res:?}")
1691        }
1692
1693        assert_snapshot!(matches(literal_sig!(p1), literal_sig!(q1), None), @"[(@p1, @q1)]");
1694        assert_snapshot!(matches(literal_sig!(p1, p2), literal_sig!(q1), None), @"[(@p1, @q1)]");
1695        assert_snapshot!(matches(literal_sig!(p1, p2), literal_sig!(q1, q2), None), @"[(@p1, @q1), (@p2, @q2)]");
1696        assert_snapshot!(matches(literal_sig!(p1), literal_sig!(q1, q2), None), @"[(@p1, @q1)]");
1697
1698        assert_snapshot!(matches(literal_sig!(p1, ...r1), literal_sig!(q1), None), @"[(@p1, @q1)]");
1699        assert_snapshot!(matches(literal_sig!(p1, ...r1), literal_sig!(q1, q2), None), @"[(@p1, @q1), (@r1, @q2)]");
1700        assert_snapshot!(matches(literal_sig!(p1, ...r1), literal_sig!(q1, q2, q3), None), @"[(@p1, @q1), (@r1, @q2), (@r1, @q3)]");
1701        assert_snapshot!(matches(literal_sig!(...r1), literal_sig!(q1, q2), None), @"[(@r1, @q1), (@r1, @q2)]");
1702
1703        assert_snapshot!(matches(literal_sig!(p1), literal_sig!(q1, ...s2), None), @"[(@p1, @q1)]");
1704        assert_snapshot!(matches(literal_sig!(p1, p2), literal_sig!(q1, ...s2), None), @"[(@p1, @q1), (@p2, @s2)]");
1705        assert_snapshot!(matches(literal_sig!(p1, p2, p3), literal_sig!(q1, ...s2), None), @"[(@p1, @q1), (@p2, @s2), (@p3, @s2)]");
1706        assert_snapshot!(matches(literal_sig!(p1, p2), literal_sig!(...s2), None), @"[(@p1, @s2), (@p2, @s2)]");
1707
1708        assert_snapshot!(matches(literal_sig!(p1, ...r1), literal_sig!(q1, ...s2), None), @"[(@p1, @q1), (@r1, @s2)]");
1709        assert_snapshot!(matches(literal_sig!(...r1), literal_sig!(q1, ...s2), None), @"[(@r1, @q1), (@r1, @s2)]");
1710        assert_snapshot!(matches(literal_sig!(p1, ...r1), literal_sig!(...s2), None), @"[(@p1, @s2), (@r1, @s2)]");
1711        assert_snapshot!(matches(literal_sig!(...r1), literal_sig!(...s2), None), @"[(@r1, @s2)]");
1712
1713        assert_snapshot!(matches(literal_sig!(p0, p1, ...r1), literal_sig!(q1, ...s2), None), @"[(@p0, @q1), (@p1, @s2), (@r1, @s2)]");
1714        assert_snapshot!(matches(literal_sig!(p0, p1, ...r1), literal_sig!(...s2), None), @"[(@p0, @s2), (@p1, @s2), (@r1, @s2)]");
1715
1716        assert_snapshot!(matches(literal_sig!(p1, ...r1), literal_sig!(q0, q1, ...s2), None), @"[(@p1, @q0), (@r1, @q1), (@r1, @s2)]");
1717        assert_snapshot!(matches(literal_sig!(...r1), literal_sig!(q0, q1, ...s2), None), @"[(@r1, @q0), (@r1, @q1), (@r1, @s2)]");
1718
1719        assert_snapshot!(matches(literal_sig!(p1 !u1: w1), literal_sig!(q1 !u1: w2), None), @"[(@p1, @q1), (@w1, @w2)]");
1720        assert_snapshot!(matches(literal_sig!(p1 !u1: w1, ...r1), literal_sig!(q1 !u1: w2), None), @"[(@p1, @q1), (@w1, @w2)]");
1721        assert_snapshot!(matches(literal_sig!(p1 !u1: w1), literal_sig!(q1 !u1: w2, ...s2), None), @"[(@p1, @q1), (@w1, @w2)]");
1722        assert_snapshot!(matches(literal_sig!(p1 !u1: w1, ...r1), literal_sig!(q1 !u1: w2, ...s2), None), @"[(@p1, @q1), (@r1, @s2), (@w1, @w2)]");
1723
1724        assert_snapshot!(matches(literal_sig!(), literal_sig!(!u1: w2), None), @"[]");
1725        assert_snapshot!(matches(literal_sig!(!u1: w1), literal_sig!(), None), @"[]");
1726        assert_snapshot!(matches(literal_sig!(!u1: w1), literal_sig!(!u1: w2), None), @"[(@w1, @w2)]");
1727        assert_snapshot!(matches(literal_sig!(!u1: w1), literal_sig!(!u2: w2), None), @"[]");
1728        assert_snapshot!(matches(literal_sig!(!u2: w1), literal_sig!(!u1: w2), None), @"[]");
1729        assert_snapshot!(matches(literal_sig!(!u1: w1, !u2: w3), literal_sig!(!u1: w2, !u2: w4), None), @"[(@w1, @w2), (@w3, @w4)]");
1730        assert_snapshot!(matches(literal_sig!(!u1: w1, !u2: w3), literal_sig!(!u2: w2, !u1: w4), None), @"[(@w1, @w4), (@w3, @w2)]");
1731        assert_snapshot!(matches(literal_sig!(!u2: w1), literal_sig!(!u1: w2, !u2: w4), None), @"[(@w1, @w4)]");
1732        assert_snapshot!(matches(literal_sig!(!u1: w1, !u2: w2), literal_sig!(!u2: w4), None), @"[(@w2, @w4)]");
1733
1734        assert_snapshot!(matches(literal_sig!(p1 !u1: w1, !u2: w2), literal_sig!(q1), Some(vec![
1735            literal_sig!(!u2: w6),
1736        ])), @"[(@p1, @q1), (@w2, @w6)]");
1737        assert_snapshot!(matches(literal_sig!(p1 !u1: w1, !u2: w2), literal_sig!(q1 !u2: w4), Some(vec![
1738            literal_sig!(!u2: w5),
1739        ])), @"[(@p1, @q1), (@w2, @w5), (@w2, @w4)]");
1740        assert_snapshot!(matches(literal_sig!(p1 !u1: w1, !u2: w2), literal_sig!(q1 ), Some(vec![
1741            literal_sig!(!u2: w7),
1742            literal_sig!(!u2: w8),
1743        ])), @"[(@p1, @q1), (@w2, @w8), (@w2, @w7)]");
1744        assert_snapshot!(matches(literal_sig!(p1, p2, p3), literal_sig!(q1), Some(vec![
1745            literal_sig!(q2),
1746            literal_sig!(q3),
1747        ])), @"[(@p1, @q3), (@p2, @q2), (@p3, @q1)]");
1748    }
1749}