tinymist_analysis/ty/
bound.rs

1use std::ops::Deref;
2
3use typst::foundations::{self, Func};
4
5use crate::ty::prelude::*;
6
7/// A trait for checking the bounds of a type.
8pub trait BoundChecker: Sized + TyCtx {
9    /// Collects the bounds of a type.
10    fn collect(&mut self, ty: &Ty, pol: bool);
11
12    /// Checks the bounds of a variable.
13    fn check_var(&mut self, u: &Interned<TypeVar>, pol: bool) {
14        self.check_var_rec(u, pol);
15    }
16
17    /// Checks the bounds of a variable recursively.
18    fn check_var_rec(&mut self, u: &Interned<TypeVar>, pol: bool) {
19        let Some(w) = self.global_bounds(u, pol) else {
20            return;
21        };
22        let mut ctx = BoundCheckContext;
23        ctx.tys(w.ubs.iter(), pol, self);
24        ctx.tys(w.lbs.iter(), !pol, self);
25    }
26}
27
28/// A predicate for checking the bounds of a type.
29#[derive(BindTyCtx)]
30#[bind(0)]
31pub struct BoundPred<'a, T: TyCtx, F>(pub &'a T, pub F);
32
33impl<'a, T: TyCtx, F> BoundPred<'a, T, F> {
34    /// Creates a new bound predicate.
35    pub fn new(t: &'a T, f: F) -> Self {
36        Self(t, f)
37    }
38}
39
40impl<T: TyCtx, F> BoundChecker for BoundPred<'_, T, F>
41where
42    F: FnMut(&Ty, bool),
43{
44    fn collect(&mut self, ty: &Ty, pol: bool) {
45        self.1(ty, pol);
46    }
47}
48
49/// A source of documentation.
50#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
51pub enum DocSource {
52    /// A variable source.
53    Var(Interned<TypeVar>),
54    /// An (value) instance source.
55    Ins(Interned<InsTy>),
56    /// A builtin type source.
57    Builtin(BuiltinTy),
58}
59
60impl DocSource {
61    /// Casts doc source to a function.
62    pub fn as_func(&self) -> Option<Func> {
63        match self {
64            Self::Var(..) => None,
65            Self::Builtin(BuiltinTy::Type(ty)) => Some(ty.constructor().ok()?),
66            Self::Builtin(BuiltinTy::Element(ty)) => Some((*ty).into()),
67            Self::Builtin(..) => None,
68            Self::Ins(ins_ty) => match &ins_ty.val {
69                foundations::Value::Func(func) => Some(func.clone()),
70                foundations::Value::Type(ty) => Some(ty.constructor().ok()?),
71                _ => None,
72            },
73        }
74    }
75}
76
77impl Ty {
78    /// Checks if the given type has bounds (is combinated).
79    pub fn has_bounds(&self) -> bool {
80        matches!(self, Ty::Union(_) | Ty::Let(_) | Ty::Var(_))
81    }
82
83    /// Converts a type to doc source.
84    pub fn as_source(&self) -> Option<DocSource> {
85        match self {
86            Ty::Builtin(ty @ (BuiltinTy::Type(..) | BuiltinTy::Element(..))) => {
87                Some(DocSource::Builtin(ty.clone()))
88            }
89            Ty::Value(ty) => match &ty.val {
90                foundations::Value::Type(..) | foundations::Value::Func(..) => {
91                    Some(DocSource::Ins(ty.clone()))
92                }
93                _ => None,
94            },
95            _ => None,
96        }
97    }
98
99    /// Gets the sources of the given type.
100    pub fn sources(&self) -> Vec<DocSource> {
101        let mut results = vec![];
102        fn collect(ty: &Ty, results: &mut Vec<DocSource>) {
103            use Ty::*;
104            if let Some(src) = ty.as_source() {
105                results.push(src);
106                return;
107            }
108            match ty {
109                Any | Boolean(_) | If(..) | Builtin(..) | Value(..) => {}
110                Dict(..) | Array(..) | Tuple(..) | Func(..) | Args(..) | Pattern(..) => {}
111                Unary(..) | Binary(..) => {}
112                Param(ty) => {
113                    // todo: doc source can be param ty
114                    collect(&ty.ty, results);
115                }
116                Union(ty) => {
117                    for ty in ty.iter() {
118                        collect(ty, results);
119                    }
120                }
121                Let(ty) => {
122                    for ty in ty.ubs.iter() {
123                        collect(ty, results);
124                    }
125                    for ty in ty.lbs.iter() {
126                        collect(ty, results);
127                    }
128                }
129                Var(ty) => {
130                    results.push(DocSource::Var(ty.clone()));
131                }
132                With(ty) => collect(&ty.sig, results),
133                Select(ty) => {
134                    // todo: do this correctly
135                    if matches!(ty.select.deref(), "with" | "where") {
136                        collect(&ty.ty, results);
137                    }
138
139                    // collect(&ty.ty, results)
140                }
141            }
142        }
143
144        collect(self, &mut results);
145        results
146    }
147
148    /// Profiles the bounds of the given type.
149    pub fn bounds(&self, pol: bool, checker: &mut impl BoundChecker) {
150        BoundCheckContext.ty(self, pol, checker);
151    }
152}
153
154/// A context for checking the bounds of a type.
155pub struct BoundCheckContext;
156
157impl BoundCheckContext {
158    /// Checks the bounds of multiple types.
159    fn tys<'a>(&mut self, tys: impl Iterator<Item = &'a Ty>, pol: bool, c: &mut impl BoundChecker) {
160        for ty in tys {
161            self.ty(ty, pol, c);
162        }
163    }
164
165    /// Checks the bounds of a type.
166    fn ty(&mut self, ty: &Ty, pol: bool, checker: &mut impl BoundChecker) {
167        match ty {
168            Ty::Union(u) => {
169                self.tys(u.iter(), pol, checker);
170            }
171            Ty::Let(u) => {
172                self.tys(u.ubs.iter(), pol, checker);
173                self.tys(u.lbs.iter(), !pol, checker);
174            }
175            Ty::Var(u) => checker.check_var(u, pol),
176            // todo: calculate these operators
177            // Ty::Select(_) => {}
178            // Ty::Unary(_) => {}
179            // Ty::Binary(_) => {}
180            // Ty::If(_) => {}
181            ty => checker.collect(ty, pol),
182        }
183    }
184}