1use 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
31pub(crate) type TyRef = Interned<Ty>;
33pub(crate) type StrRef = Interned<str>;
35
36#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
38pub enum Ty {
39 Any,
43 Boolean(Option<bool>),
46 Builtin(BuiltinTy),
48 Value(Interned<InsTy>),
50 Param(Interned<ParamTy>),
52
53 Union(Interned<Vec<Ty>>),
57 Let(Interned<TypeBounds>),
60 Var(Interned<TypeVar>),
62
63 Dict(Interned<RecordTy>),
66 Array(TyRef),
68 Tuple(Interned<Vec<Ty>>),
71 Func(Interned<SigTy>),
73 Args(Interned<ArgsTy>),
75 Pattern(Interned<PatternTy>),
77
78 With(Interned<SigWithTy>),
81 Select(Interned<SelectTy>),
83 Unary(Interned<TypeUnary>),
85 Binary(Interned<TypeBinary>),
87 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 pub fn is_dict(&self) -> bool {
141 matches!(self, Ty::Dict(..))
142 }
143
144 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 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 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 pub const fn undef() -> Self {
175 Ty::Builtin(BuiltinTy::Undef)
176 }
177
178 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 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 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 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 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 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 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 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
287fn is_content_builtin_type(ty: &Type) -> bool {
289 *ty == Type::of::<Content>() || *ty == Type::of::<typst::foundations::Symbol>()
290}
291
292fn is_str_builtin_type(ty: &Type) -> bool {
294 *ty == Type::of::<typst::foundations::Str>()
295}
296
297fn is_type_builtin_type(ty: &Type) -> bool {
299 *ty == Type::of::<Type>()
300}
301
302pub enum TypeSigParam<'a> {
304 Pos(&'a Ty),
306 Named(&'a StrRef, &'a Ty),
308 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 TypeSigParam::Rest(ty) => write!(f, "...: {ty:?}"),
319 }
320 }
321}
322
323#[derive(Debug, Clone, PartialEq, Eq)]
326pub struct TypeSource {
327 pub name_node: SyntaxNode,
329 pub name_repr: OnceLock<StrRef>,
331 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 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#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
360pub struct NameBone {
361 pub names: Box<[StrRef]>,
363}
364
365impl NameBone {
366 pub fn empty() -> Interned<Self> {
368 Interned::new(Self {
369 names: Box::new([]),
370 })
371 }
372}
373
374impl NameBone {
375 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 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#[derive(Clone, Default)]
425pub struct DynTypeBounds {
426 pub lbs: rpds::RedBlackTreeSetSync<Ty>,
428 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 pub fn freeze(&self) -> TypeBounds {
444 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#[derive(Hash, Clone, PartialEq, Eq, Default, PartialOrd, Ord)]
457pub struct TypeBounds {
458 pub lbs: Vec<Ty>,
460 pub ubs: Vec<Ty>,
462}
463
464impl fmt::Debug for TypeBounds {
465 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
466 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
484pub trait TypeInterface {
487 fn bone(&self) -> &Interned<NameBone>;
490 fn interface(&self) -> impl Iterator<Item = (&StrRef, &Ty)>;
492 fn field_by_bone_offset(&self, idx: usize) -> Option<&Ty>;
494 fn field_by_name(&self, name: &StrRef) -> Option<&Ty> {
496 self.field_by_bone_offset(self.bone().find(name)?)
497 }
498}
499
500pub trait TypeInterfaceExt: TypeInterface {
502 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#[derive(Debug, Hash, Clone, PartialEq)]
524pub struct InsTy {
525 pub val: Value,
527 pub syntax: Option<Interned<TypeSource>>,
529}
530
531impl Eq for InsTy {}
534
535impl PartialOrd for Interned<InsTy> {
537 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
538 Some(self.cmp(other))
539 }
540}
541
542impl 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
557fn 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
642fn 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
665fn 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 pub fn new(val: Value) -> Interned<Self> {
764 Self { val, syntax: None }.into()
765 }
766
767 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 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 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#[derive(
812 Debug, Clone, Copy, Hash, Serialize, Deserialize, Default, PartialEq, Eq, PartialOrd, Ord,
813)]
814pub struct ParamAttrs {
815 pub positional: bool,
817 pub named: bool,
822 pub variadic: bool,
824 pub settable: bool,
826}
827
828impl ParamAttrs {
829 pub fn positional() -> ParamAttrs {
831 ParamAttrs {
832 positional: true,
833 named: false,
834 variadic: false,
835 settable: false,
836 }
837 }
838
839 pub fn named() -> ParamAttrs {
841 ParamAttrs {
842 positional: false,
843 named: true,
844 variadic: false,
845 settable: false,
846 }
847 }
848
849 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#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
873pub struct ParamTy {
874 pub name: StrRef,
876 pub docs: Option<DocText>,
878 pub default: Option<EcoString>,
880 pub ty: Ty,
882 pub attrs: ParamAttrs,
884}
885
886impl ParamTy {
887 pub fn new_untyped(name: StrRef, attrs: ParamAttrs) -> Interned<Self> {
889 Self::new(Ty::Any, name, attrs)
890 }
891
892 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#[derive(Hash, Clone, PartialEq, Eq)]
906pub struct TypeVar {
907 pub name: StrRef,
909 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 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 pub fn new(name: StrRef, def: DeclExpr) -> Interned<Self> {
942 Interned::new(Self { name, def })
943 }
944
945 pub fn name(&self) -> StrRef {
947 self.name.clone()
948 }
949}
950
951#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
953pub struct RecordTy {
954 pub names: Interned<NameBone>,
956 pub types: Interned<Vec<Ty>>,
958}
959
960impl RecordTy {
961 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 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#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
1010pub struct SigTy {
1011 pub inputs: Interned<Vec<Ty>>,
1013 pub body: Option<Ty>,
1015 pub names: Interned<NameBone>,
1017 pub name_started: u32,
1019 pub spread_left: bool,
1021 pub spread_right: bool,
1023}
1024
1025impl SigTy {
1026 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 #[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 #[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 #[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 #[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 pub fn with_body(mut self, res_ty: Ty) -> Self {
1107 self.body = Some(res_ty);
1108 self
1109 }
1110
1111 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 pub fn inputs(&self) -> impl Iterator<Item = &Ty> {
1178 self.inputs.iter()
1179 }
1180
1181 pub fn positional_params(&self) -> impl ExactSizeIterator<Item = &Ty> {
1183 self.inputs.iter().take(self.name_started as usize)
1184 }
1185
1186 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 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 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 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 pub fn rest_param(&self) -> Option<&Ty> {
1224 if self.spread_right {
1225 self.inputs.last()
1226 } else {
1227 None
1228 }
1229 }
1230
1231 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
1295pub type ArgsTy = SigTy;
1297
1298pub type PatternTy = SigTy;
1300
1301#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
1303pub struct SigWithTy {
1304 pub sig: TyRef,
1306 pub with: Interned<ArgsTy>,
1308}
1309
1310impl SigWithTy {
1311 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#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
1325pub struct SelectTy {
1326 pub ty: TyRef,
1328 pub select: StrRef,
1330}
1331
1332impl SelectTy {
1333 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#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1347pub struct TypeUnary {
1348 pub lhs: Ty,
1350 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 pub fn new(op: UnaryOp, lhs: Ty) -> Interned<Self> {
1373 Interned::new(Self { lhs, op })
1374 }
1375
1376 pub fn operands(&self) -> [&Ty; 1] {
1378 [&self.lhs]
1379 }
1380}
1381
1382pub type BinaryOp = ast::BinOp;
1384
1385#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1387pub struct TypeBinary {
1388 pub operands: (Ty, Ty),
1390 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 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 pub fn operands(&self) -> [&Ty; 2] {
1421 [&self.operands.0, &self.operands.1]
1422 }
1423}
1424
1425#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
1428pub struct IfTy {
1429 pub cond: TyRef,
1431 pub then: TyRef,
1433 pub else_: TyRef,
1435}
1436
1437impl IfTy {
1438 pub fn new(cond: TyRef, then: TyRef, else_: TyRef) -> Interned<Self> {
1440 Interned::new(Self { cond, then, else_ })
1441 }
1442}
1443
1444#[derive(Default)]
1446pub struct TypeInfo {
1447 pub valid: bool,
1449 pub fid: Option<FileId>,
1451 pub revision: usize,
1453 pub exports: FxHashMap<StrRef, Ty>,
1455 pub vars: FxHashMap<DeclExpr, TypeVarBounds>,
1457 pub var_docs: FxHashMap<DeclExpr, Arc<UntypedDefDocs>>,
1459 pub local_binds: snapshot_map::SnapshotMap<DeclExpr, Ty>,
1461 pub mapping: FxHashMap<Span, FxHashSet<Ty>>,
1463 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 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 pub fn witness_at_least(&mut self, site: Span, ty: Ty) {
1498 Self::witness_(site, ty, &mut self.mapping);
1499 }
1500 pub fn witness_at_most(&mut self, site: Span, ty: Ty) {
1502 Self::witness_(site, ty, &mut self.mapping);
1503 }
1504
1505 pub fn witness_(site: Span, ty: Ty, mapping: &mut FxHashMap<Span, FxHashSet<Ty>>) {
1507 if site.is_detached() {
1508 return;
1509 }
1510
1511 mapping.entry(site).or_default().insert(ty);
1513 }
1514
1515 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#[derive(Clone)]
1580pub struct TypeVarBounds {
1581 pub var: Interned<TypeVar>,
1583 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 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 pub fn name(&self) -> &StrRef {
1604 &self.var.name
1605 }
1606
1607 pub fn as_type(&self) -> Ty {
1609 Ty::Var(self.var.clone())
1610 }
1611
1612 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#[derive(Clone)]
1625pub enum FlowVarKind {
1626 Strong(Arc<RwLock<DynTypeBounds>>),
1628 Weak(Arc<RwLock<DynTypeBounds>>),
1631}
1632
1633impl FlowVarKind {
1634 pub fn bounds(&self) -> &RwLock<DynTypeBounds> {
1636 match self {
1637 FlowVarKind::Strong(w) | FlowVarKind::Weak(w) => w,
1638 }
1639 }
1640}
1641
1642#[derive(Default)]
1644pub(super) struct TypeCanoStore {
1645 pub cano_cache: FxHashMap<(Ty, bool), Ty>,
1647 pub transform_cache: FxHashMap<(Ty, bool), Ty>,
1649 pub cano_local_cache: FxHashMap<(DeclExpr, bool), Ty>,
1651 pub negatives: FxHashSet<DeclExpr>,
1653 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}