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, Repr, 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::{DocText, UntypedDefDocs},
24    syntax::{DeclExpr, UnaryOp, def::StrictCmp},
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.to_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.leaf_text();
348                if !name.is_empty() {
349                    return name.into();
350                }
351                let name = self.name_node.clone().full_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///
420/// The bound sets iterate in content order. [`Interned`] hashes by pointer
421/// address, so a hash-based set would iterate in allocation order, which
422/// depends on thread scheduling; checker invocation order over the bounds
423/// would then leak scheduling into inferred types.
424#[derive(Clone, Default)]
425pub struct DynTypeBounds {
426    /// The lower bounds
427    pub lbs: rpds::RedBlackTreeSetSync<Ty>,
428    /// The upper bounds
429    pub ubs: rpds::RedBlackTreeSetSync<Ty>,
430}
431
432impl From<TypeBounds> for DynTypeBounds {
433    fn from(bounds: TypeBounds) -> Self {
434        Self {
435            lbs: bounds.lbs.into_iter().collect(),
436            ubs: bounds.ubs.into_iter().collect(),
437        }
438    }
439}
440
441impl DynTypeBounds {
442    /// Gets the frozen bounds.
443    pub fn freeze(&self) -> TypeBounds {
444        // sorted
445        let mut lbs: Vec<_> = self.lbs.iter().cloned().collect();
446        lbs.sort();
447        let mut ubs: Vec<_> = self.ubs.iter().cloned().collect();
448        ubs.sort();
449        TypeBounds { lbs, ubs }
450    }
451}
452
453/// A frozen type variable (bounds of some type in program).
454/// `t :> t1 | ... | tn <: f1 & ... & fn`
455/// `  lbs------------- ubs-------------`
456#[derive(Hash, Clone, PartialEq, Eq, Default, PartialOrd, Ord)]
457pub struct TypeBounds {
458    /// The lower bounds.
459    pub lbs: Vec<Ty>,
460    /// The upper bounds.
461    pub ubs: Vec<Ty>,
462}
463
464impl fmt::Debug for TypeBounds {
465    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
466        // write!(f, "{}", self.name)
467        // also where
468        if !self.lbs.is_empty() {
469            write!(f, " ⪰ {:?}", self.lbs[0])?;
470            for lb in &self.lbs[1..] {
471                write!(f, " | {lb:?}")?;
472            }
473        }
474        if !self.ubs.is_empty() {
475            write!(f, " ⪯ {:?}", self.ubs[0])?;
476            for ub in &self.ubs[1..] {
477                write!(f, " & {ub:?}")?;
478            }
479        }
480        Ok(())
481    }
482}
483
484/// A common type kinds for those types that has fields (abstracted record
485/// type).
486pub trait TypeInterface {
487    /// Gets the bone of a record.
488    /// See [`NameBone`] for more details.
489    fn bone(&self) -> &Interned<NameBone>;
490    /// Iterates over the fields of a record.
491    fn interface(&self) -> impl Iterator<Item = (&StrRef, &Ty)>;
492    /// Gets the field by bone offset.
493    fn field_by_bone_offset(&self, idx: usize) -> Option<&Ty>;
494    /// Gets the field by name.
495    fn field_by_name(&self, name: &StrRef) -> Option<&Ty> {
496        self.field_by_bone_offset(self.bone().find(name)?)
497    }
498}
499
500/// Extension common methods for [`TypeInterface`].
501pub trait TypeInterfaceExt: TypeInterface {
502    /// Convenience method to get the common fields of two records.
503    fn common_iface_fields<'a>(
504        &'a self,
505        rhs: &'a Self,
506    ) -> impl Iterator<Item = (&'a StrRef, &'a Ty, &'a Ty)> {
507        let lhs_names = self.bone();
508        let rhs_names = rhs.bone();
509
510        lhs_names
511            .intersect_enumerate(rhs_names)
512            .filter_map(move |(i, j)| {
513                let lhs = self.field_by_bone_offset(i)?;
514                let rhs = rhs.field_by_bone_offset(j)?;
515                Some((&lhs_names.names[i], lhs, rhs))
516            })
517    }
518}
519
520impl<T: TypeInterface> TypeInterfaceExt for T {}
521
522/// An instance of a typst type.
523#[derive(Debug, Hash, Clone, PartialEq)]
524pub struct InsTy {
525    /// The value of the instance.
526    pub val: Value,
527    /// The syntax source of the instance.
528    pub syntax: Option<Interned<TypeSource>>,
529}
530
531/// There are some case that val is not Eq, but we make it Eq for simplicity
532/// For example, a float instance which is NaN.
533impl Eq for InsTy {}
534
535/// Orders instances by stable value content; see [`Ord`] on this type.
536impl PartialOrd for Interned<InsTy> {
537    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
538        Some(self.cmp(other))
539    }
540}
541
542/// Orders instances by stable value content ([`cmp_value`]), never by raw
543/// interned identity or address.
544///
545/// Distinct instances with equal values are tie-broken by their syntax
546/// source content, so ordered collections do not collapse two instances that
547/// pointer equality keeps apart.
548impl Ord for Interned<InsTy> {
549    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
550        if self == other {
551            return std::cmp::Ordering::Equal;
552        }
553        cmp_value(&self.val, &other.val).then_with(|| cmp_type_source(&self.syntax, &other.syntax))
554    }
555}
556
557/// Orders syntax sources by stable content. Span identities are not used:
558/// they embed file ids assigned in interning order, which depends on thread
559/// scheduling.
560fn cmp_type_source(
561    x: &Option<Interned<TypeSource>>,
562    y: &Option<Interned<TypeSource>>,
563) -> std::cmp::Ordering {
564    use std::cmp::Ordering;
565    match (x, y) {
566        (None, None) => Ordering::Equal,
567        (None, Some(_)) => Ordering::Less,
568        (Some(_), None) => Ordering::Greater,
569        (Some(x), Some(y)) => {
570            if x == y {
571                return Ordering::Equal;
572            }
573            let file = |source: &TypeSource| source.name_node.span().id();
574            file(x)
575                .strict_cmp(&file(y))
576                .then_with(|| x.name().cmp(&y.name()))
577                .then_with(|| x.doc.cmp(&y.doc))
578        }
579    }
580}
581
582fn cmp_value(x: &Value, y: &Value) -> std::cmp::Ordering {
583    match x.partial_cmp(y) {
584        Some(order) => return order,
585        None => {
586            let x_dis = val_discriminant(x);
587            let y_dis = val_discriminant(y);
588            if x_dis != y_dis {
589                return x_dis.cmp(&y_dis);
590            }
591        }
592    }
593
594    match (&x, &y) {
595        (Value::Str(x), Value::Str(y)) => x.cmp(y),
596        (Value::Bool(x), Value::Bool(y)) => x.cmp(y),
597        (Value::Int(x), Value::Int(y)) => x.cmp(y),
598        (Value::Decimal(x), Value::Decimal(y)) => x.cmp(y),
599        (Value::Angle(x), Value::Angle(y)) => x.cmp(y),
600        (Value::Ratio(x), Value::Ratio(y)) => x.cmp(y),
601        (Value::Fraction(x), Value::Fraction(y)) => x.cmp(y),
602        (Value::Version(x), Value::Version(y)) => x.cmp(y),
603        (Value::Bytes(x), Value::Bytes(y)) => x.cmp(y),
604        (Value::Duration(x), Value::Duration(y)) => x.cmp(y),
605        (Value::Type(x), Value::Type(y)) => x.long_name().cmp(y.long_name()),
606        (Value::None, Value::None) | (Value::Auto, Value::Auto) => std::cmp::Ordering::Equal,
607        (Value::Array(x), Value::Array(y)) => cmp_by(x.iter(), y.iter(), cmp_value),
608        (Value::Dict(x), Value::Dict(y)) => cmp_by(x.iter(), y.iter(), |(xk, xv), (yk, yv)| {
609            xk.cmp(yk).then_with(|| cmp_value(xv, yv))
610        }),
611        (Value::Label(x), Value::Label(y)) => x.resolve().cmp(&y.resolve()),
612        (Value::Float(x), Value::Float(y)) => x.to_bits().cmp(&y.to_bits()),
613        (Value::Length(x), Value::Length(y)) => x.abs.cmp(&y.abs).then_with(|| x.em.cmp(&y.em)),
614        (Value::Relative(x), Value::Relative(y)) => x.rel.cmp(&y.rel).then_with(|| {
615            x.abs
616                .abs
617                .cmp(&y.abs.abs)
618                .then_with(|| x.abs.em.cmp(&y.abs.em))
619        }),
620        (Value::Func(x), Value::Func(y)) => cmp_func(x, y),
621        (Value::Args(x), Value::Args(y)) => x.span.strict_cmp(&y.span).then_with(|| repr_cmp(x, y)),
622        (Value::Module(x), Value::Module(y)) => match (x.file_id(), y.file_id()) {
623            (Some(x), Some(y)) => x.strict_cmp(&y),
624            (Some(..), None) => std::cmp::Ordering::Less,
625            (None, Some(..)) => std::cmp::Ordering::Greater,
626            (None, None) => repr_cmp(x, y),
627        },
628        (Value::Datetime(x), Value::Datetime(y)) => {
629            x.partial_cmp(y).unwrap_or_else(|| repr_cmp(x, y))
630        }
631        (Value::Color(x), Value::Color(y)) => repr_cmp(x, y),
632        (Value::Gradient(x), Value::Gradient(y)) => repr_cmp(x, y),
633        (Value::Tiling(x), Value::Tiling(y)) => repr_cmp(x, y),
634        (Value::Symbol(x), Value::Symbol(y)) => repr_cmp(x, y),
635        (Value::Content(x), Value::Content(y)) => repr_cmp(x, y),
636        (Value::Styles(x), Value::Styles(y)) => repr_cmp(x, y),
637        (Value::Dyn(x), Value::Dyn(y)) => repr_cmp(x, y),
638        _ => x.repr().cmp(&y.repr()),
639    }
640}
641
642/// Compares functions by content-stable identity: the name, source location,
643/// definition site, and finally the display representation. Raw span and
644/// pointer identities depend on interning and allocation order, which vary
645/// with thread scheduling and across processes. The definition site is needed
646/// because native methods with different receivers share a name and detached
647/// span (for example, `array.at` and `str.at`).
648fn cmp_func(x: &typst::foundations::Func, y: &typst::foundations::Func) -> std::cmp::Ordering {
649    use typst::foundations::FuncInner;
650    x.name()
651        .cmp(&y.name())
652        .then_with(|| x.span().strict_cmp(&y.span()))
653        .then_with(|| match (x.def_site(), y.def_site()) {
654            (Some(x), Some(y)) => x.path.cmp(y.path).then_with(|| x.key.cmp(y.key)),
655            (Some(..), None) => std::cmp::Ordering::Less,
656            (None, Some(..)) => std::cmp::Ordering::Greater,
657            (None, None) => std::cmp::Ordering::Equal,
658        })
659        .then_with(|| match (x.inner(), y.inner()) {
660            (FuncInner::Element(x), FuncInner::Element(y)) => x.name().cmp(y.name()),
661            _ => repr_cmp(x, y),
662        })
663}
664
665/// Compares by display representation as the content-stable last resort.
666/// Distinct values with an identical representation compare equal; an
667/// ordered collection may then keep only one of them, which is acceptable
668/// because they also render identically everywhere the type is shown.
669fn repr_cmp<T: Repr>(x: &T, y: &T) -> std::cmp::Ordering {
670    x.repr().cmp(&y.repr())
671}
672
673fn cmp_by<T>(
674    mut x_iter: impl Iterator<Item = T>,
675    mut y_iter: impl Iterator<Item = T>,
676    mut cmp: impl FnMut(T, T) -> std::cmp::Ordering,
677) -> std::cmp::Ordering {
678    use std::cmp::Ordering;
679    loop {
680        match (x_iter.next(), y_iter.next()) {
681            (Some(x_item), Some(y_item)) => match cmp(x_item, y_item) {
682                Ordering::Equal => continue,
683                other => return other,
684            },
685            (Some(_), None) => return Ordering::Greater,
686            (None, Some(_)) => return Ordering::Less,
687            (None, None) => return Ordering::Equal,
688        }
689    }
690}
691
692fn val_discriminant(val: &Value) -> TypstValueEnum {
693    match val {
694        Value::Str(..) => TypstValueEnum::Str,
695        Value::None => TypstValueEnum::None,
696        Value::Auto => TypstValueEnum::Auto,
697        Value::Array(..) => TypstValueEnum::Array,
698        Value::Args(..) => TypstValueEnum::Args,
699        Value::Dict(..) => TypstValueEnum::Dict,
700        Value::Module(..) => TypstValueEnum::Module,
701        Value::Func(..) => TypstValueEnum::Func,
702        Value::Label(..) => TypstValueEnum::Label,
703        Value::Bool(..) => TypstValueEnum::Bool,
704        Value::Int(..) => TypstValueEnum::Int,
705        Value::Float(..) => TypstValueEnum::Float,
706        Value::Decimal(..) => TypstValueEnum::Decimal,
707        Value::Length(..) => TypstValueEnum::Length,
708        Value::Angle(..) => TypstValueEnum::Angle,
709        Value::Ratio(..) => TypstValueEnum::Ratio,
710        Value::Relative(..) => TypstValueEnum::Relative,
711        Value::Fraction(..) => TypstValueEnum::Fraction,
712        Value::Color(..) => TypstValueEnum::Color,
713        Value::Gradient(..) => TypstValueEnum::Gradient,
714        Value::Tiling(..) => TypstValueEnum::Tiling,
715        Value::Symbol(..) => TypstValueEnum::Symbol,
716        Value::Version(..) => TypstValueEnum::Version,
717        Value::Bytes(..) => TypstValueEnum::Bytes,
718        Value::Datetime(..) => TypstValueEnum::Datetime,
719        Value::Duration(..) => TypstValueEnum::Duration,
720        Value::Content(..) => TypstValueEnum::Content,
721        Value::Styles(..) => TypstValueEnum::Styles,
722        Value::Type(..) => TypstValueEnum::Type,
723        Value::Dyn(..) => TypstValueEnum::Dyn,
724    }
725}
726
727#[derive(PartialEq, Eq, PartialOrd, Ord)]
728enum TypstValueEnum {
729    Str,
730    None,
731    Auto,
732    Array,
733    Args,
734    Dict,
735    Module,
736    Func,
737    Label,
738    Bool,
739    Int,
740    Float,
741    Decimal,
742    Length,
743    Angle,
744    Ratio,
745    Relative,
746    Fraction,
747    Color,
748    Gradient,
749    Tiling,
750    Symbol,
751    Version,
752    Bytes,
753    Datetime,
754    Duration,
755    Content,
756    Styles,
757    Type,
758    Dyn,
759}
760
761impl InsTy {
762    /// Creates an instance.
763    pub fn new(val: Value) -> Interned<Self> {
764        Self { val, syntax: None }.into()
765    }
766
767    /// Creates an instance with a sapn.
768    pub fn new_at(val: Value, span: Span) -> Interned<Self> {
769        let mut name = SyntaxNode::leaf(SyntaxKind::Ident, "");
770        name.synthesize(span);
771        Interned::new(Self {
772            val,
773            syntax: Some(Interned::new(TypeSource {
774                name_node: name,
775                name_repr: OnceLock::new(),
776                doc: "".into(),
777            })),
778        })
779    }
780
781    /// Creates an instance with a documentation string.
782    pub fn new_doc(val: Value, doc: impl Into<StrRef>) -> Interned<Self> {
783        Interned::new(Self {
784            val,
785            syntax: Some(Interned::new(TypeSource {
786                name_node: SyntaxNode::default(),
787                name_repr: OnceLock::new(),
788                doc: doc.into(),
789            })),
790        })
791    }
792
793    /// Gets the span of the instance.
794    pub fn span(&self) -> Span {
795        self.syntax
796            .as_ref()
797            .map(|source| source.name_node.span())
798            .or_else(|| {
799                Some(match &self.val {
800                    Value::Func(func) => func.span(),
801                    Value::Args(args) => args.span,
802                    Value::Content(content) => content.span(),
803                    _ => return None,
804                })
805            })
806            .unwrap_or_else(Span::detached)
807    }
808}
809
810/// Describes a function parameter attribute.
811#[derive(
812    Debug, Clone, Copy, Hash, Serialize, Deserialize, Default, PartialEq, Eq, PartialOrd, Ord,
813)]
814pub struct ParamAttrs {
815    /// Whether the parameter is positional.
816    pub positional: bool,
817    /// Whether the parameter is named.
818    ///
819    /// Can be true even if `positional` is true if the parameter can be given
820    /// in both variants.
821    pub named: bool,
822    /// Whether the parameter can be given any number of times.
823    pub variadic: bool,
824    /// Whether the parameter is settable with a set rule.
825    pub settable: bool,
826}
827
828impl ParamAttrs {
829    /// Creates a positional parameter attribute.
830    pub fn positional() -> ParamAttrs {
831        ParamAttrs {
832            positional: true,
833            named: false,
834            variadic: false,
835            settable: false,
836        }
837    }
838
839    /// Creates a named parameter attribute.
840    pub fn named() -> ParamAttrs {
841        ParamAttrs {
842            positional: false,
843            named: true,
844            variadic: false,
845            settable: false,
846        }
847    }
848
849    /// Creates a variadic parameter attribute.
850    pub fn variadic() -> ParamAttrs {
851        ParamAttrs {
852            positional: true,
853            named: false,
854            variadic: true,
855            settable: false,
856        }
857    }
858}
859
860impl From<&ParamInfo> for ParamAttrs {
861    fn from(param: &ParamInfo) -> Self {
862        ParamAttrs {
863            positional: param.positional(),
864            named: param.named(),
865            variadic: param.variadic(),
866            settable: param.settable(),
867        }
868    }
869}
870
871/// Describes a parameter type.
872#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
873pub struct ParamTy {
874    /// The name of the parameter.
875    pub name: StrRef,
876    /// The docstring of the parameter.
877    pub docs: Option<DocText>,
878    /// The default value of the variable.
879    pub default: Option<EcoString>,
880    /// The type of the parameter.
881    pub ty: Ty,
882    /// The attributes of the parameter.
883    pub attrs: ParamAttrs,
884}
885
886impl ParamTy {
887    /// Creates an untyped field type.
888    pub fn new_untyped(name: StrRef, attrs: ParamAttrs) -> Interned<Self> {
889        Self::new(Ty::Any, name, attrs)
890    }
891
892    /// Creates a typed field type.
893    pub fn new(ty: Ty, name: StrRef, attrs: ParamAttrs) -> Interned<Self> {
894        Interned::new(Self {
895            name,
896            ty,
897            docs: None,
898            default: None,
899            attrs,
900        })
901    }
902}
903
904/// A type variable.
905#[derive(Hash, Clone, PartialEq, Eq)]
906pub struct TypeVar {
907    /// The name of the type variable.
908    pub name: StrRef,
909    /// The definition id of the type variable.
910    pub def: DeclExpr,
911}
912
913impl Ord for TypeVar {
914    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
915        self.def.strict_cmp(&other.def)
916    }
917}
918
919impl TypeVar {
920    /// Low-performance comparison but it is free from the concurrency issue.
921    /// This is only used for making stable test snapshots.
922    pub fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
923        self.def.strict_cmp(&other.def)
924    }
925}
926
927impl PartialOrd for TypeVar {
928    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
929        Some(self.cmp(other))
930    }
931}
932
933impl fmt::Debug for TypeVar {
934    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
935        write!(f, "@{}", self.name)
936    }
937}
938
939impl TypeVar {
940    /// Creates a type variable.
941    pub fn new(name: StrRef, def: DeclExpr) -> Interned<Self> {
942        Interned::new(Self { name, def })
943    }
944
945    /// Gets the name of the type variable.
946    pub fn name(&self) -> StrRef {
947        self.name.clone()
948    }
949}
950
951/// A record type.
952#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
953pub struct RecordTy {
954    /// The names of the fields.
955    pub names: Interned<NameBone>,
956    /// The types of the fields.
957    pub types: Interned<Vec<Ty>>,
958}
959
960impl RecordTy {
961    /// Shapes the fields of a record.
962    pub fn shape_fields(mut fields: Vec<(StrRef, Ty)>) -> (NameBone, Vec<Ty>) {
963        fields.sort_by(|a, b| a.0.cmp(&b.0));
964        let names = NameBone {
965            names: fields.iter().map(|(name, _)| name.clone()).collect(),
966        };
967        let types = fields.into_iter().map(|(_, ty)| ty).collect::<Vec<_>>();
968
969        (names, types)
970    }
971
972    /// Creates a record type.
973    pub fn new(fields: Vec<(StrRef, Ty)>) -> Interned<Self> {
974        let (names, types) = Self::shape_fields(fields);
975        Interned::new(Self {
976            types: Interned::new(types),
977            names: Interned::new(names),
978        })
979    }
980}
981
982impl TypeInterface for RecordTy {
983    fn bone(&self) -> &Interned<NameBone> {
984        &self.names
985    }
986
987    fn field_by_bone_offset(&self, idx: usize) -> Option<&Ty> {
988        self.types.get(idx)
989    }
990
991    fn interface(&self) -> impl Iterator<Item = (&StrRef, &Ty)> {
992        self.names.names.iter().zip(self.types.iter())
993    }
994}
995
996impl fmt::Debug for RecordTy {
997    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
998        f.write_str("{")?;
999        interpersed(
1000            f,
1001            self.interface()
1002                .map(|(name, ty)| TypeSigParam::Named(name, ty)),
1003        )?;
1004        f.write_str("}")
1005    }
1006}
1007
1008/// A typst function type.
1009#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
1010pub struct SigTy {
1011    /// The input types of the function.
1012    pub inputs: Interned<Vec<Ty>>,
1013    /// The return (body) type of the function.
1014    pub body: Option<Ty>,
1015    /// The name bone of the named parameters.
1016    pub names: Interned<NameBone>,
1017    /// The index of the first named parameter.
1018    pub name_started: u32,
1019    /// Whether the function has a spread left parameter.
1020    pub spread_left: bool,
1021    /// Whether the function has a spread right parameter.
1022    pub spread_right: bool,
1023}
1024
1025impl SigTy {
1026    /// Creates an function that accepts any arguments: `(a, b: c, ..d)`
1027    pub fn any() -> Interned<SigTy> {
1028        let rest = Ty::Array(Interned::new(Ty::Any));
1029        Interned::new(Self {
1030            inputs: Interned::new(vec![rest]),
1031            body: Some(Ty::Any),
1032            names: NameBone::empty(),
1033            name_started: 0,
1034            spread_left: false,
1035            spread_right: true,
1036        })
1037    }
1038
1039    /// Creates an array constructor: `(a)`
1040    #[comemo::memoize]
1041    pub fn array_cons(elem: Ty, anyify: bool) -> Interned<SigTy> {
1042        let rest = Ty::Array(Interned::new(elem.clone()));
1043        let ret = if anyify { Ty::Any } else { rest.clone() };
1044        Interned::new(Self {
1045            inputs: Interned::new(vec![rest]),
1046            body: Some(ret),
1047            names: NameBone::empty(),
1048            name_started: 0,
1049            spread_left: false,
1050            spread_right: true,
1051        })
1052    }
1053
1054    /// Creates a unary constructor: `(a) => b`
1055    #[comemo::memoize]
1056    pub fn unary(inp: Ty, ret: Ty) -> Interned<SigTy> {
1057        Interned::new(Self {
1058            inputs: Interned::new(vec![inp]),
1059            body: Some(ret),
1060            names: NameBone::empty(),
1061            name_started: 1,
1062            spread_left: false,
1063            spread_right: false,
1064        })
1065    }
1066
1067    /// Creates a tuple constructor: `(a, b, c)`
1068    #[comemo::memoize]
1069    pub fn tuple_cons(elems: Interned<Vec<Ty>>, anyify: bool) -> Interned<SigTy> {
1070        let ret = if anyify {
1071            Ty::Any
1072        } else {
1073            Ty::Tuple(elems.clone())
1074        };
1075        let name_started = elems.len() as u32;
1076        Interned::new(Self {
1077            inputs: elems,
1078            body: Some(ret),
1079            names: NameBone::empty(),
1080            name_started,
1081            spread_left: false,
1082            spread_right: false,
1083        })
1084    }
1085
1086    /// Creates a dictionary constructor: `(a: b, c: d)`
1087    #[comemo::memoize]
1088    pub fn dict_cons(named: &Interned<RecordTy>, anyify: bool) -> Interned<SigTy> {
1089        let ret = if anyify {
1090            Ty::Any
1091        } else {
1092            Ty::Dict(named.clone())
1093        };
1094
1095        Interned::new(Self {
1096            inputs: named.types.clone(),
1097            body: Some(ret),
1098            names: named.names.clone(),
1099            name_started: 0,
1100            spread_left: false,
1101            spread_right: false,
1102        })
1103    }
1104
1105    /// Sets the return type of the function.
1106    pub fn with_body(mut self, res_ty: Ty) -> Self {
1107        self.body = Some(res_ty);
1108        self
1109    }
1110
1111    /// Creates a function type.
1112    pub fn new(
1113        pos: impl ExactSizeIterator<Item = Ty>,
1114        named: impl IntoIterator<Item = (StrRef, Ty)>,
1115        rest_left: Option<Ty>,
1116        rest_right: Option<Ty>,
1117        ret_ty: Option<Ty>,
1118    ) -> Self {
1119        let named = named.into_iter().collect::<Vec<_>>();
1120        let (names, mut named_types) = RecordTy::shape_fields(named);
1121        let spread_left = rest_left.is_some();
1122        let spread_right = rest_right.is_some();
1123
1124        let name_started = if spread_right { 1 } else { 0 } + named_types.len();
1125        let mut types = Vec::with_capacity(
1126            pos.len() + named_types.len() + spread_left as usize + spread_right as usize,
1127        );
1128        types.extend(pos);
1129        types.append(&mut named_types);
1130        types.extend(rest_left);
1131        types.extend(rest_right);
1132
1133        let name_started = (types.len() - name_started) as u32;
1134
1135        Self {
1136            inputs: Interned::new(types),
1137            body: ret_ty,
1138            names: Interned::new(names),
1139            name_started,
1140            spread_left,
1141            spread_right,
1142        }
1143    }
1144}
1145
1146impl Default for SigTy {
1147    fn default() -> Self {
1148        Self {
1149            inputs: Interned::new(Vec::new()),
1150            body: None,
1151            names: NameBone::empty(),
1152            name_started: 0,
1153            spread_left: false,
1154            spread_right: false,
1155        }
1156    }
1157}
1158
1159impl TypeInterface for SigTy {
1160    fn bone(&self) -> &Interned<NameBone> {
1161        &self.names
1162    }
1163
1164    fn interface(&self) -> impl Iterator<Item = (&StrRef, &Ty)> {
1165        let names = self.names.names.iter();
1166        let types = self.inputs.iter().skip(self.name_started as usize);
1167        names.zip(types)
1168    }
1169
1170    fn field_by_bone_offset(&self, offset: usize) -> Option<&Ty> {
1171        self.inputs.get(offset + self.name_started as usize)
1172    }
1173}
1174
1175impl SigTy {
1176    /// Gets the input types of the function.
1177    pub fn inputs(&self) -> impl Iterator<Item = &Ty> {
1178        self.inputs.iter()
1179    }
1180
1181    /// Gets the positional parameters of the function.
1182    pub fn positional_params(&self) -> impl ExactSizeIterator<Item = &Ty> {
1183        self.inputs.iter().take(self.name_started as usize)
1184    }
1185
1186    /// Gets the parameter at the given index.
1187    pub fn pos(&self, idx: usize) -> Option<&Ty> {
1188        (idx < self.name_started as usize)
1189            .then_some(())
1190            .and_then(|_| self.inputs.get(idx))
1191    }
1192
1193    /// Gets the parameter or the rest parameter at the given index.
1194    pub fn pos_or_rest(&self, idx: usize) -> Option<Ty> {
1195        let nth = self.pos(idx).cloned();
1196        nth.or_else(|| {
1197            let rest_idx = || idx.saturating_sub(self.positional_params().len());
1198
1199            let rest_ty = self.rest_param()?;
1200            match rest_ty {
1201                Ty::Array(ty) => Some(ty.as_ref().clone()),
1202                Ty::Tuple(tys) => tys.get(rest_idx()).cloned(),
1203                _ => None,
1204            }
1205        })
1206    }
1207
1208    /// Gets the named parameters of the function.
1209    pub fn named_params(&self) -> impl ExactSizeIterator<Item = (&StrRef, &Ty)> {
1210        let named_names = self.names.names.iter();
1211        let named_types = self.inputs.iter().skip(self.name_started as usize);
1212
1213        named_names.zip(named_types)
1214    }
1215
1216    /// Gets the named parameter by given name.
1217    pub fn named(&self, name: &StrRef) -> Option<&Ty> {
1218        let idx = self.names.find(name)?;
1219        self.inputs.get(idx + self.name_started as usize)
1220    }
1221
1222    /// Gets the rest parameter of the function.
1223    pub fn rest_param(&self) -> Option<&Ty> {
1224        if self.spread_right {
1225            self.inputs.last()
1226        } else {
1227            None
1228        }
1229    }
1230
1231    /// Matches the function type with the given arguments.
1232    pub fn matches<'a>(
1233        &'a self,
1234        args: &'a SigTy,
1235        with: Option<&'a Vec<Interned<SigTy>>>,
1236    ) -> impl Iterator<Item = (&'a Ty, &'a Ty)> + 'a {
1237        let with_len = with
1238            .map(|w| w.iter().map(|w| w.positional_params().len()).sum::<usize>())
1239            .unwrap_or(0);
1240
1241        let sig_pos = self.positional_params();
1242        let arg_pos = args.positional_params();
1243
1244        let sig_rest = self.rest_param();
1245        let arg_rest = args.rest_param();
1246
1247        let max_len = sig_pos.len().max(with_len + arg_pos.len())
1248            + if sig_rest.is_some() && arg_rest.is_some() {
1249                1
1250            } else {
1251                0
1252            };
1253
1254        let arg_pos = with
1255            .into_iter()
1256            .flat_map(|w| w.iter().rev().map(|w| w.positional_params()))
1257            .flatten()
1258            .chain(arg_pos);
1259
1260        let sig_stream = sig_pos.chain(sig_rest.into_iter().cycle()).take(max_len);
1261        let arg_stream = arg_pos.chain(arg_rest.into_iter().cycle()).take(max_len);
1262
1263        let pos = sig_stream.zip(arg_stream);
1264        let common_ifaces = with
1265            .map(|args_all| args_all.iter().rev())
1266            .into_iter()
1267            .flatten()
1268            .flat_map(|args| self.common_iface_fields(args))
1269            .chain(self.common_iface_fields(args));
1270        let named = common_ifaces.map(|(_, l, r)| (l, r));
1271
1272        pos.chain(named)
1273    }
1274}
1275
1276impl fmt::Debug for SigTy {
1277    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1278        f.write_str("(")?;
1279        let pos = self.positional_params().map(TypeSigParam::Pos);
1280        let named = self
1281            .named_params()
1282            .map(|(name, ty)| TypeSigParam::Named(name, ty));
1283        let rest = self.rest_param().map(TypeSigParam::Rest);
1284        interpersed(f, pos.chain(named).chain(rest))?;
1285        f.write_str(") => ")?;
1286        if let Some(ret) = &self.body {
1287            ret.fmt(f)?;
1288        } else {
1289            f.write_str("any")?;
1290        }
1291        Ok(())
1292    }
1293}
1294
1295/// A function argument type.
1296pub type ArgsTy = SigTy;
1297
1298/// A pattern type.
1299pub type PatternTy = SigTy;
1300
1301/// A type with partially applied arguments.
1302#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
1303pub struct SigWithTy {
1304    /// The signature of the function.
1305    pub sig: TyRef,
1306    /// The arguments applied to the function.
1307    pub with: Interned<ArgsTy>,
1308}
1309
1310impl SigWithTy {
1311    /// Creates a type with applied arguments.
1312    pub fn new(sig: TyRef, with: Interned<ArgsTy>) -> Interned<Self> {
1313        Interned::new(Self { sig, with })
1314    }
1315}
1316
1317impl fmt::Debug for SigWithTy {
1318    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1319        write!(f, "{:?}.with({:?})", self.sig, self.with)
1320    }
1321}
1322
1323/// A field selection type.
1324#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
1325pub struct SelectTy {
1326    /// The type to select from.
1327    pub ty: TyRef,
1328    /// The field to select
1329    pub select: StrRef,
1330}
1331
1332impl SelectTy {
1333    /// Creates a field selection type.
1334    pub fn new(ty: TyRef, select: StrRef) -> Interned<Self> {
1335        Interned::new(Self { ty, select })
1336    }
1337}
1338
1339impl fmt::Debug for SelectTy {
1340    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1341        write!(f, "{:?}.{}", RefDebug(&self.ty), self.select)
1342    }
1343}
1344
1345/// A unary operation type.
1346#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1347pub struct TypeUnary {
1348    /// The operand of the unary operation.
1349    pub lhs: Ty,
1350    /// The kind of the unary operation
1351    pub op: UnaryOp,
1352}
1353
1354impl PartialOrd for TypeUnary {
1355    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1356        Some(self.cmp(other))
1357    }
1358}
1359
1360impl Ord for TypeUnary {
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.lhs.cmp(&other.lhs))
1367    }
1368}
1369
1370impl TypeUnary {
1371    /// Creates a unary operation type.
1372    pub fn new(op: UnaryOp, lhs: Ty) -> Interned<Self> {
1373        Interned::new(Self { lhs, op })
1374    }
1375
1376    /// Gets the operands of the unary operation.
1377    pub fn operands(&self) -> [&Ty; 1] {
1378        [&self.lhs]
1379    }
1380}
1381
1382/// The kind of binary operation.
1383pub type BinaryOp = ast::BinOp;
1384
1385/// A binary operation type.
1386#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1387pub struct TypeBinary {
1388    /// The operands of the binary operation.
1389    pub operands: (Ty, Ty),
1390    /// The kind of the binary operation.
1391    pub op: BinaryOp,
1392}
1393
1394impl PartialOrd for TypeBinary {
1395    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1396        Some(self.cmp(other))
1397    }
1398}
1399
1400impl Ord for TypeBinary {
1401    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1402        let op_as_int = self.op as u8;
1403        let other_op_as_int = other.op as u8;
1404        op_as_int
1405            .cmp(&other_op_as_int)
1406            .then_with(|| self.operands.cmp(&other.operands))
1407    }
1408}
1409
1410impl TypeBinary {
1411    /// Creates a binary operation type.
1412    pub fn new(op: BinaryOp, lhs: Ty, rhs: Ty) -> Interned<Self> {
1413        Interned::new(Self {
1414            operands: (lhs, rhs),
1415            op,
1416        })
1417    }
1418
1419    /// Gets the operands of the binary operation.
1420    pub fn operands(&self) -> [&Ty; 2] {
1421        [&self.operands.0, &self.operands.1]
1422    }
1423}
1424
1425/// A conditional type.
1426/// `if t1 then t2 else t3`
1427#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
1428pub struct IfTy {
1429    /// The condition.
1430    pub cond: TyRef,
1431    /// The type when the condition is true.
1432    pub then: TyRef,
1433    /// The type when the condition is false.
1434    pub else_: TyRef,
1435}
1436
1437impl IfTy {
1438    /// Creates a conditional type.
1439    pub fn new(cond: TyRef, then: TyRef, else_: TyRef) -> Interned<Self> {
1440        Interned::new(Self { cond, then, else_ })
1441    }
1442}
1443
1444/// The type information on a group of syntax structures (typing).
1445#[derive(Default)]
1446pub struct TypeInfo {
1447    /// Whether the typing is valid.
1448    pub valid: bool,
1449    /// The belonging file id.
1450    pub fid: Option<FileId>,
1451    /// The used revision.
1452    pub revision: usize,
1453    /// The exported types.
1454    pub exports: FxHashMap<StrRef, Ty>,
1455    /// The typing on definitions.
1456    pub vars: FxHashMap<DeclExpr, TypeVarBounds>,
1457    /// The checked documentation of definitions.
1458    pub var_docs: FxHashMap<DeclExpr, Arc<UntypedDefDocs>>,
1459    /// The local binding of the type variable.
1460    pub local_binds: snapshot_map::SnapshotMap<DeclExpr, Ty>,
1461    /// The typing on syntax structures.
1462    pub mapping: FxHashMap<Span, FxHashSet<Ty>>,
1463    /// The cache to canonicalize types.
1464    pub(super) cano_cache: Mutex<TypeCanoStore>,
1465}
1466
1467impl Hash for TypeInfo {
1468    fn hash<H: Hasher>(&self, state: &mut H) {
1469        self.valid.hash(state);
1470        self.fid.hash(state);
1471        self.revision.hash(state);
1472    }
1473}
1474
1475impl TyCtx for TypeInfo {
1476    fn global_bounds(&self, var: &Interned<TypeVar>, _pol: bool) -> Option<DynTypeBounds> {
1477        let v = self.vars.get(&var.def)?;
1478        Some(v.bounds.bounds().read().clone())
1479    }
1480
1481    fn local_bind_of(&self, var: &Interned<TypeVar>) -> Option<Ty> {
1482        self.local_binds.get(&var.def).cloned()
1483    }
1484}
1485
1486impl TypeInfo {
1487    /// Gets the type of a syntax structure.
1488    pub fn type_of_span(&self, site: Span) -> Option<Ty> {
1489        self.mapping
1490            .get(&site)
1491            .cloned()
1492            .map(|types| Ty::from_types(types.into_iter()))
1493    }
1494
1495    // todo: distinguish at least, at most
1496    /// Witnesses a lower-bound type on a syntax structure.
1497    pub fn witness_at_least(&mut self, site: Span, ty: Ty) {
1498        Self::witness_(site, ty, &mut self.mapping);
1499    }
1500    /// Witnesses a upper-bound type on a syntax structure.
1501    pub fn witness_at_most(&mut self, site: Span, ty: Ty) {
1502        Self::witness_(site, ty, &mut self.mapping);
1503    }
1504
1505    /// Witnesses a type.
1506    pub fn witness_(site: Span, ty: Ty, mapping: &mut FxHashMap<Span, FxHashSet<Ty>>) {
1507        if site.is_detached() {
1508            return;
1509        }
1510
1511        // todo: intersect/union
1512        mapping.entry(site).or_default().insert(ty);
1513    }
1514
1515    /// Converts a type to a type with bounds.
1516    pub fn to_bounds(&self, def: Ty) -> DynTypeBounds {
1517        let mut store = DynTypeBounds::default();
1518        match def {
1519            Ty::Var(v) => {
1520                let w = self.vars.get(&v.def).unwrap();
1521                match &w.bounds {
1522                    FlowVarKind::Strong(bounds) | FlowVarKind::Weak(bounds) => {
1523                        let w = bounds.read();
1524                        for bound in w.lbs.iter() {
1525                            store.lbs.insert_mut(bound.clone());
1526                        }
1527                        for bound in w.ubs.iter() {
1528                            store.ubs.insert_mut(bound.clone());
1529                        }
1530                    }
1531                }
1532            }
1533            Ty::Let(bounds) => {
1534                for bound in bounds.lbs.iter() {
1535                    store.lbs.insert_mut(bound.clone());
1536                }
1537                for bound in bounds.ubs.iter() {
1538                    store.ubs.insert_mut(bound.clone());
1539                }
1540            }
1541            _ => {
1542                store.ubs.insert_mut(def);
1543            }
1544        }
1545
1546        store
1547    }
1548}
1549
1550impl TyCtxMut for TypeInfo {
1551    type Snap = ena::undo_log::Snapshot;
1552
1553    fn start_scope(&mut self) -> Self::Snap {
1554        self.local_binds.snapshot()
1555    }
1556
1557    fn end_scope(&mut self, snap: Self::Snap) {
1558        self.local_binds.rollback_to(snap);
1559    }
1560
1561    fn bind_local(&mut self, var: &Interned<TypeVar>, ty: Ty) {
1562        self.local_binds.insert(var.def.clone(), ty);
1563    }
1564
1565    fn type_of_func(&mut self, _func: &typst::foundations::Func) -> Option<Interned<SigTy>> {
1566        None
1567    }
1568
1569    fn type_of_value(&mut self, _val: &Value) -> Ty {
1570        Ty::Any
1571    }
1572
1573    fn check_module_item(&mut self, _module: FileId, _key: &StrRef) -> Option<Ty> {
1574        None
1575    }
1576}
1577
1578/// A type variable bounds.
1579#[derive(Clone)]
1580pub struct TypeVarBounds {
1581    /// The type variable representation.
1582    pub var: Interned<TypeVar>,
1583    /// The bounds of the type variable.
1584    pub bounds: FlowVarKind,
1585}
1586
1587impl fmt::Debug for TypeVarBounds {
1588    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1589        write!(f, "{:?}", self.var)
1590    }
1591}
1592
1593impl TypeVarBounds {
1594    /// Creates a type variable bounds.
1595    pub fn new(var: TypeVar, init: DynTypeBounds) -> Self {
1596        Self {
1597            var: Interned::new(var),
1598            bounds: FlowVarKind::Strong(Arc::new(RwLock::new(init.clone()))),
1599        }
1600    }
1601
1602    /// Gets the name of the type variable.
1603    pub fn name(&self) -> &StrRef {
1604        &self.var.name
1605    }
1606
1607    /// Gets self as a type.
1608    pub fn as_type(&self) -> Ty {
1609        Ty::Var(self.var.clone())
1610    }
1611
1612    /// Slightly closes the type variable.
1613    pub fn weaken(&mut self) {
1614        match &self.bounds {
1615            FlowVarKind::Strong(w) => {
1616                self.bounds = FlowVarKind::Weak(w.clone());
1617            }
1618            FlowVarKind::Weak(_) => {}
1619        }
1620    }
1621}
1622
1623/// A type variable bounds.
1624#[derive(Clone)]
1625pub enum FlowVarKind {
1626    /// A type variable that receives both types and values (type instances).
1627    Strong(Arc<RwLock<DynTypeBounds>>),
1628    /// A type variable that receives only types.
1629    /// The received values will be lifted to types.
1630    Weak(Arc<RwLock<DynTypeBounds>>),
1631}
1632
1633impl FlowVarKind {
1634    /// Gets the bounds of the type variable.
1635    pub fn bounds(&self) -> &RwLock<DynTypeBounds> {
1636        match self {
1637            FlowVarKind::Strong(w) | FlowVarKind::Weak(w) => w,
1638        }
1639    }
1640}
1641
1642/// A cache to canonicalize types.
1643#[derive(Default)]
1644pub(super) struct TypeCanoStore {
1645    /// Maps a type to its canonical form.
1646    pub cano_cache: FxHashMap<(Ty, bool), Ty>,
1647    /// Memoizes sub-type transforms within one simplify call.
1648    pub transform_cache: FxHashMap<(Ty, bool), Ty>,
1649    /// Maps a local type to its canonical form.
1650    pub cano_local_cache: FxHashMap<(DeclExpr, bool), Ty>,
1651    /// The negative bounds of a type variable.
1652    pub negatives: FxHashSet<DeclExpr>,
1653    /// The positive bounds of a type variable.
1654    pub positives: FxHashSet<DeclExpr>,
1655}
1656
1657impl_internable!(Ty,);
1658impl_internable!(InsTy,);
1659impl_internable!(ParamTy,);
1660impl_internable!(TypeSource,);
1661impl_internable!(TypeVar,);
1662impl_internable!(SigWithTy,);
1663impl_internable!(SigTy,);
1664impl_internable!(RecordTy,);
1665impl_internable!(SelectTy,);
1666impl_internable!(TypeUnary,);
1667impl_internable!(TypeBinary,);
1668impl_internable!(IfTy,);
1669impl_internable!(Vec<Ty>,);
1670impl_internable!(TypeBounds,);
1671impl_internable!(NameBone,);
1672impl_internable!(PackageId,);
1673impl_internable!((Ty, Ty),);
1674
1675struct RefDebug<'a>(&'a Ty);
1676
1677impl fmt::Debug for RefDebug<'_> {
1678    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1679        match self.0 {
1680            Ty::Var(v) => write!(f, "@v{:?}", v.name()),
1681            _ => write!(f, "{:?}", self.0),
1682        }
1683    }
1684}
1685
1686fn interpersed<T: fmt::Debug>(
1687    f: &mut fmt::Formatter<'_>,
1688    iter: impl Iterator<Item = T>,
1689) -> fmt::Result {
1690    let mut first = true;
1691    for arg in iter {
1692        if first {
1693            first = false;
1694        } else {
1695            f.write_str(", ")?;
1696        }
1697        arg.fmt(f)?;
1698    }
1699    Ok(())
1700}
1701
1702#[cfg(test)]
1703mod tests {
1704    use insta::{assert_debug_snapshot, assert_snapshot};
1705
1706    use crate::ty::tests::*;
1707
1708    #[test]
1709    fn test_ty_size() {
1710        use super::*;
1711        assert!(size_of::<Ty>() <= size_of::<usize>() * 2);
1712    }
1713
1714    #[test]
1715    fn test_ty() {
1716        use super::*;
1717        let ty = Ty::Builtin(BuiltinTy::Clause);
1718        let ty_ref = TyRef::new(ty.clone());
1719        assert_debug_snapshot!(ty_ref, @"Clause");
1720    }
1721
1722    #[test]
1723    fn native_method_order_uses_definition_site() {
1724        use super::*;
1725        use typst::foundations::{Array, Bytes, Dict, Str, Type, Value, Version};
1726
1727        fn method(ty: Type, name: &str) -> typst::foundations::Func {
1728            match ty.scope().get(name).expect("native method").read() {
1729                Value::Func(func) => func.clone(),
1730                _ => panic!("native method is not a function"),
1731            }
1732        }
1733
1734        let methods = [
1735            method(Type::of::<Array>(), "at"),
1736            method(Type::of::<Bytes>(), "at"),
1737            method(Type::of::<Dict>(), "at"),
1738            method(Type::of::<Str>(), "at"),
1739            method(Type::of::<Version>(), "at"),
1740        ];
1741
1742        for (idx, lhs) in methods.iter().enumerate() {
1743            for rhs in &methods[idx + 1..] {
1744                assert_ne!(lhs, rhs);
1745                assert_ne!(cmp_func(lhs, rhs), std::cmp::Ordering::Equal);
1746                assert_eq!(cmp_func(lhs, rhs), cmp_func(rhs, lhs).reverse());
1747            }
1748        }
1749    }
1750
1751    #[test]
1752    fn test_sig_matches() {
1753        use super::*;
1754
1755        fn matches(
1756            sig: Interned<SigTy>,
1757            args: Interned<SigTy>,
1758            with: Option<Vec<Interned<ArgsTy>>>,
1759        ) -> String {
1760            let res = sig.matches(&args, with.as_ref()).collect::<Vec<_>>();
1761            format!("{res:?}")
1762        }
1763
1764        assert_snapshot!(matches(literal_sig!(p1), literal_sig!(q1), None), @"[(@p1, @q1)]");
1765        assert_snapshot!(matches(literal_sig!(p1, p2), literal_sig!(q1), None), @"[(@p1, @q1)]");
1766        assert_snapshot!(matches(literal_sig!(p1, p2), literal_sig!(q1, q2), None), @"[(@p1, @q1), (@p2, @q2)]");
1767        assert_snapshot!(matches(literal_sig!(p1), literal_sig!(q1, q2), None), @"[(@p1, @q1)]");
1768
1769        assert_snapshot!(matches(literal_sig!(p1, ...r1), literal_sig!(q1), None), @"[(@p1, @q1)]");
1770        assert_snapshot!(matches(literal_sig!(p1, ...r1), literal_sig!(q1, q2), None), @"[(@p1, @q1), (@r1, @q2)]");
1771        assert_snapshot!(matches(literal_sig!(p1, ...r1), literal_sig!(q1, q2, q3), None), @"[(@p1, @q1), (@r1, @q2), (@r1, @q3)]");
1772        assert_snapshot!(matches(literal_sig!(...r1), literal_sig!(q1, q2), None), @"[(@r1, @q1), (@r1, @q2)]");
1773
1774        assert_snapshot!(matches(literal_sig!(p1), literal_sig!(q1, ...s2), None), @"[(@p1, @q1)]");
1775        assert_snapshot!(matches(literal_sig!(p1, p2), literal_sig!(q1, ...s2), None), @"[(@p1, @q1), (@p2, @s2)]");
1776        assert_snapshot!(matches(literal_sig!(p1, p2, p3), literal_sig!(q1, ...s2), None), @"[(@p1, @q1), (@p2, @s2), (@p3, @s2)]");
1777        assert_snapshot!(matches(literal_sig!(p1, p2), literal_sig!(...s2), None), @"[(@p1, @s2), (@p2, @s2)]");
1778
1779        assert_snapshot!(matches(literal_sig!(p1, ...r1), literal_sig!(q1, ...s2), None), @"[(@p1, @q1), (@r1, @s2)]");
1780        assert_snapshot!(matches(literal_sig!(...r1), literal_sig!(q1, ...s2), None), @"[(@r1, @q1), (@r1, @s2)]");
1781        assert_snapshot!(matches(literal_sig!(p1, ...r1), literal_sig!(...s2), None), @"[(@p1, @s2), (@r1, @s2)]");
1782        assert_snapshot!(matches(literal_sig!(...r1), literal_sig!(...s2), None), @"[(@r1, @s2)]");
1783
1784        assert_snapshot!(matches(literal_sig!(p0, p1, ...r1), literal_sig!(q1, ...s2), None), @"[(@p0, @q1), (@p1, @s2), (@r1, @s2)]");
1785        assert_snapshot!(matches(literal_sig!(p0, p1, ...r1), literal_sig!(...s2), None), @"[(@p0, @s2), (@p1, @s2), (@r1, @s2)]");
1786
1787        assert_snapshot!(matches(literal_sig!(p1, ...r1), literal_sig!(q0, q1, ...s2), None), @"[(@p1, @q0), (@r1, @q1), (@r1, @s2)]");
1788        assert_snapshot!(matches(literal_sig!(...r1), literal_sig!(q0, q1, ...s2), None), @"[(@r1, @q0), (@r1, @q1), (@r1, @s2)]");
1789
1790        assert_snapshot!(matches(literal_sig!(p1 !u1: w1), literal_sig!(q1 !u1: w2), None), @"[(@p1, @q1), (@w1, @w2)]");
1791        assert_snapshot!(matches(literal_sig!(p1 !u1: w1, ...r1), literal_sig!(q1 !u1: w2), None), @"[(@p1, @q1), (@w1, @w2)]");
1792        assert_snapshot!(matches(literal_sig!(p1 !u1: w1), literal_sig!(q1 !u1: w2, ...s2), None), @"[(@p1, @q1), (@w1, @w2)]");
1793        assert_snapshot!(matches(literal_sig!(p1 !u1: w1, ...r1), literal_sig!(q1 !u1: w2, ...s2), None), @"[(@p1, @q1), (@r1, @s2), (@w1, @w2)]");
1794
1795        assert_snapshot!(matches(literal_sig!(), literal_sig!(!u1: w2), None), @"[]");
1796        assert_snapshot!(matches(literal_sig!(!u1: w1), literal_sig!(), None), @"[]");
1797        assert_snapshot!(matches(literal_sig!(!u1: w1), literal_sig!(!u1: w2), None), @"[(@w1, @w2)]");
1798        assert_snapshot!(matches(literal_sig!(!u1: w1), literal_sig!(!u2: w2), None), @"[]");
1799        assert_snapshot!(matches(literal_sig!(!u2: w1), literal_sig!(!u1: w2), None), @"[]");
1800        assert_snapshot!(matches(literal_sig!(!u1: w1, !u2: w3), literal_sig!(!u1: w2, !u2: w4), None), @"[(@w1, @w2), (@w3, @w4)]");
1801        assert_snapshot!(matches(literal_sig!(!u1: w1, !u2: w3), literal_sig!(!u2: w2, !u1: w4), None), @"[(@w1, @w4), (@w3, @w2)]");
1802        assert_snapshot!(matches(literal_sig!(!u2: w1), literal_sig!(!u1: w2, !u2: w4), None), @"[(@w1, @w4)]");
1803        assert_snapshot!(matches(literal_sig!(!u1: w1, !u2: w2), literal_sig!(!u2: w4), None), @"[(@w2, @w4)]");
1804
1805        assert_snapshot!(matches(literal_sig!(p1 !u1: w1, !u2: w2), literal_sig!(q1), Some(vec![
1806            literal_sig!(!u2: w6),
1807        ])), @"[(@p1, @q1), (@w2, @w6)]");
1808        assert_snapshot!(matches(literal_sig!(p1 !u1: w1, !u2: w2), literal_sig!(q1 !u2: w4), Some(vec![
1809            literal_sig!(!u2: w5),
1810        ])), @"[(@p1, @q1), (@w2, @w5), (@w2, @w4)]");
1811        assert_snapshot!(matches(literal_sig!(p1 !u1: w1, !u2: w2), literal_sig!(q1 ), Some(vec![
1812            literal_sig!(!u2: w7),
1813            literal_sig!(!u2: w8),
1814        ])), @"[(@p1, @q1), (@w2, @w8), (@w2, @w7)]");
1815        assert_snapshot!(matches(literal_sig!(p1, p2, p3), literal_sig!(q1), Some(vec![
1816            literal_sig!(q2),
1817            literal_sig!(q3),
1818        ])), @"[(@p1, @q3), (@p2, @q2), (@p3, @q1)]");
1819    }
1820}