tinymist_analysis/ty/
sig.rs

1use typst::foundations::{Func, Value};
2
3use super::BoundChecker;
4use crate::ty::prelude::*;
5
6/// A signature.
7#[derive(Debug, Clone, Copy)]
8pub enum Sig<'a> {
9    /// A builtin signature.        
10    Builtin(BuiltinSig<'a>),
11    /// A type signature.
12    Type(&'a Interned<SigTy>),
13    /// A type constructor.
14    TypeCons {
15        /// The type.
16        val: &'a typst::foundations::Type,
17        /// The original type.
18        at: &'a Ty,
19    },
20    /// An array constructor.
21    ArrayCons(&'a TyRef),
22    /// A tuple constructor.
23    TupleCons(&'a Interned<Vec<Ty>>),
24    /// A dictionary constructor.
25    DictCons(&'a Interned<RecordTy>),
26    /// A value signature.
27    Value {
28        /// The value.
29        val: &'a Func,
30        /// The original type.
31        at: &'a Ty,
32    },
33    /// A partialize signature.
34    Partialize(&'a Sig<'a>),
35    /// A with signature.
36    With {
37        /// The signature.
38        sig: &'a Sig<'a>,
39        /// The bounds.
40        withs: &'a Vec<Interned<ArgsTy>>,
41        /// The original type.
42        at: &'a Ty,
43    },
44}
45
46/// A shape of a signature.
47pub struct SigShape<'a> {
48    /// The signature.
49    pub sig: Interned<SigTy>,
50    /// The withs.
51    pub withs: Option<&'a Vec<Interned<SigTy>>>,
52}
53
54impl<'a> Sig<'a> {
55    /// Gets the type of the signature.
56    pub fn ty(self) -> Option<Ty> {
57        Some(match self {
58            Sig::Builtin(_) => return None,
59            Sig::Type(t) => Ty::Func(t.clone()),
60            Sig::ArrayCons(t) => Ty::Array(t.clone()),
61            Sig::TupleCons(t) => Ty::Tuple(t.clone()),
62            Sig::DictCons(t) => Ty::Dict(t.clone()),
63            Sig::TypeCons { val, .. } => Ty::Builtin(BuiltinTy::Type(*val)),
64            Sig::Value { at, .. } => at.clone(),
65            Sig::With { at, .. } => at.clone(),
66            Sig::Partialize(..) => return None,
67        })
68    }
69
70    /// Gets the shape of the signature.
71    pub fn shape(self, ctx: &mut impl TyCtxMut) -> Option<SigShape<'a>> {
72        let (sig, _is_partialize) = match self {
73            Sig::Partialize(sig) => (*sig, true),
74            sig => (sig, false),
75        };
76
77        let (cano_sig, withs) = match sig {
78            Sig::With { sig, withs, .. } => (*sig, Some(withs)),
79            sig => (sig, None),
80        };
81
82        let sig = match cano_sig {
83            Sig::Builtin(_) => return None,
84            Sig::ArrayCons(arr) => SigTy::array_cons(arr.as_ref().clone(), false),
85            Sig::TupleCons(tup) => SigTy::tuple_cons(tup.clone(), false),
86            Sig::DictCons(dict) => SigTy::dict_cons(dict, false),
87            Sig::TypeCons { val, .. } => ctx.type_of_func(&val.constructor().ok()?)?,
88            Sig::Value { val, .. } => ctx.type_of_func(val)?,
89            // todo
90            Sig::Partialize(..) => return None,
91            Sig::With { .. } => return None,
92            Sig::Type(ty) => ty.clone(),
93        };
94
95        Some(SigShape { sig, withs })
96    }
97}
98
99/// A kind of signature surface.
100#[derive(Debug, Clone, Copy, PartialEq, Eq)]
101pub enum SigSurfaceKind {
102    /// A call signature.
103    Call,
104    /// An array signature.
105    Array,
106    /// A dictionary signature.
107    Dict,
108    /// An array or dictionary signature.
109    ArrayOrDict,
110}
111
112/// A trait to check a signature.
113pub trait SigChecker: TyCtx {
114    /// Checks the signature.
115    fn check(&mut self, sig: Sig, args: &mut SigCheckContext, pol: bool) -> Option<()>;
116}
117
118impl Ty {
119    /// Iterate over the signatures of the given type.
120    pub fn sig_surface(&self, pol: bool, sig_kind: SigSurfaceKind, checker: &mut impl SigChecker) {
121        let ctx = SigCheckContext {
122            sig_kind,
123            args: Vec::new(),
124            at: TyRef::new(Ty::Any),
125        };
126
127        SigCheckDriver { ctx, checker }.ty(self, pol);
128    }
129
130    /// Get the signature representation of the given type.
131    pub fn sig_repr(&self, pol: bool, ctx: &mut impl TyCtxMut) -> Option<Interned<SigTy>> {
132        // todo: union sig
133        // let mut pos = vec![];
134        // let mut named = HashMap::new();
135        // let mut rest = None;
136        // let mut ret = None;
137
138        let mut primary = None;
139
140        #[derive(BindTyCtx)]
141        #[bind(0)]
142        struct SigReprDriver<'a, C: TyCtxMut>(&'a mut C, &'a mut Option<Interned<SigTy>>);
143
144        impl<C: TyCtxMut> SigChecker for SigReprDriver<'_, C> {
145            fn check(&mut self, sig: Sig, _ctx: &mut SigCheckContext, _pol: bool) -> Option<()> {
146                let sig = sig.shape(self.0)?;
147                *self.1 = Some(sig.sig.clone());
148                Some(())
149            }
150        }
151
152        self.sig_surface(
153            pol,
154            SigSurfaceKind::Call,
155            // todo: bind type context
156            &mut SigReprDriver(ctx, &mut primary),
157        );
158
159        primary
160    }
161}
162
163/// A context to check a signature.
164pub struct SigCheckContext {
165    /// The kind of signature surface.
166    pub sig_kind: SigSurfaceKind,
167    /// The arguments.
168    pub args: Vec<Interned<SigTy>>,
169    /// The type.
170    pub at: TyRef,
171}
172
173/// A driver to check a signature.
174#[derive(BindTyCtx)]
175#[bind(checker)]
176pub struct SigCheckDriver<'a> {
177    ctx: SigCheckContext,
178    checker: &'a mut dyn SigChecker,
179}
180
181impl SigCheckDriver<'_> {
182    /// Determines whether the signature is a function.
183    fn func_as_sig(&self) -> bool {
184        matches!(self.ctx.sig_kind, SigSurfaceKind::Call)
185    }
186
187    /// Determines whether the signature is an array.
188    fn array_as_sig(&self) -> bool {
189        matches!(
190            self.ctx.sig_kind,
191            SigSurfaceKind::Array | SigSurfaceKind::ArrayOrDict
192        )
193    }
194
195    /// Determines whether the signature is a dictionary.
196    fn dict_as_sig(&self) -> bool {
197        matches!(
198            self.ctx.sig_kind,
199            SigSurfaceKind::Dict | SigSurfaceKind::ArrayOrDict
200        )
201    }
202
203    /// Checks the signature of the given type.
204    fn ty(&mut self, at: &Ty, pol: bool) {
205        crate::log_debug_ct!("check sig: {at:?}");
206        match at {
207            Ty::Builtin(BuiltinTy::Stroke) if self.dict_as_sig() => {
208                self.checker
209                    .check(Sig::DictCons(&FLOW_STROKE_DICT), &mut self.ctx, pol);
210            }
211            Ty::Builtin(BuiltinTy::Margin) if self.dict_as_sig() => {
212                self.checker
213                    .check(Sig::DictCons(&FLOW_MARGIN_DICT), &mut self.ctx, pol);
214            }
215            Ty::Builtin(BuiltinTy::Inset) if self.dict_as_sig() => {
216                self.checker
217                    .check(Sig::DictCons(&FLOW_INSET_DICT), &mut self.ctx, pol);
218            }
219            Ty::Builtin(BuiltinTy::Outset) if self.dict_as_sig() => {
220                self.checker
221                    .check(Sig::DictCons(&FLOW_OUTSET_DICT), &mut self.ctx, pol);
222            }
223            Ty::Builtin(BuiltinTy::Radius) if self.dict_as_sig() => {
224                self.checker
225                    .check(Sig::DictCons(&FLOW_RADIUS_DICT), &mut self.ctx, pol);
226            }
227            Ty::Builtin(BuiltinTy::TextFont) if self.dict_as_sig() => {
228                self.checker
229                    .check(Sig::DictCons(&FLOW_TEXT_FONT_DICT), &mut self.ctx, pol);
230            }
231            // todo: deduplicate checking early
232            Ty::Value(ins_ty) => {
233                if self.func_as_sig() {
234                    match &ins_ty.val {
235                        Value::Func(func) => {
236                            self.checker
237                                .check(Sig::Value { val: func, at }, &mut self.ctx, pol);
238                        }
239                        Value::Type(ty) => {
240                            self.checker
241                                .check(Sig::TypeCons { val: ty, at }, &mut self.ctx, pol);
242                        }
243                        _ => {}
244                    }
245                }
246            }
247            Ty::Builtin(BuiltinTy::Type(b_ty)) if self.func_as_sig() => {
248                // todo: distinguish between element and function
249                self.checker
250                    .check(Sig::TypeCons { val: b_ty, at }, &mut self.ctx, pol);
251            }
252            Ty::Builtin(BuiltinTy::Element(elem)) if self.func_as_sig() => {
253                // todo: distinguish between element and function
254                let func = (*elem).into();
255                self.checker
256                    .check(Sig::Value { val: &func, at }, &mut self.ctx, pol);
257            }
258            Ty::Func(sig) if self.func_as_sig() => {
259                self.checker.check(Sig::Type(sig), &mut self.ctx, pol);
260            }
261            Ty::Array(arr) if self.array_as_sig() => {
262                self.checker.check(Sig::ArrayCons(arr), &mut self.ctx, pol);
263            }
264            Ty::Tuple(elems) if self.array_as_sig() => {
265                self.checker
266                    .check(Sig::TupleCons(elems), &mut self.ctx, pol);
267            }
268            Ty::Dict(sig) if self.dict_as_sig() => {
269                // self.check_dict_signature(sig, pol, self.checker);
270                self.checker.check(Sig::DictCons(sig), &mut self.ctx, pol);
271            }
272            Ty::With(sig) if self.func_as_sig() => {
273                self.ctx.args.push(sig.with.clone());
274                self.ty(&sig.sig, pol);
275                self.ctx.args.pop();
276            }
277            Ty::Select(sel) => sel.ty.bounds(pol, &mut MethodDriver(self, &sel.select)),
278            // todo: calculate these operators
279            Ty::Unary(_) => {}
280            Ty::Binary(_) => {}
281            Ty::If(_) => {}
282            Ty::Param(param) => {
283                // todo: keep type information
284                self.ty(&param.ty, pol);
285            }
286            _ if at.has_bounds() => at.bounds(pol, self),
287            _ => {}
288        }
289    }
290}
291
292impl BoundChecker for SigCheckDriver<'_> {
293    fn collect(&mut self, ty: &Ty, pol: bool) {
294        crate::log_debug_ct!("sig bounds: {ty:?}");
295        self.ty(ty, pol);
296    }
297}
298
299/// A driver to check a method.
300#[derive(BindTyCtx)]
301#[bind(0)]
302struct MethodDriver<'a, 'b>(&'a mut SigCheckDriver<'b>, &'a StrRef);
303
304impl MethodDriver<'_, '_> {
305    fn is_binder(&self) -> bool {
306        matches!(self.1.as_ref(), "with" | "where")
307    }
308
309    fn array_method(&mut self, ty: &Ty, pol: bool) {
310        let method = match self.1.as_ref() {
311            "map" => BuiltinSig::TupleMap(ty),
312            "at" => BuiltinSig::TupleAt(ty),
313            _ => return,
314        };
315        self.0
316            .checker
317            .check(Sig::Builtin(method), &mut self.0.ctx, pol);
318    }
319}
320
321impl BoundChecker for MethodDriver<'_, '_> {
322    fn collect(&mut self, ty: &Ty, pol: bool) {
323        crate::log_debug_ct!("check method: {ty:?}.{}", self.1.as_ref());
324        match ty {
325            // todo: deduplicate checking early
326            Ty::Value(v) => {
327                match &v.val {
328                    Value::Func(func) => {
329                        if self.is_binder() {
330                            self.0.checker.check(
331                                Sig::Partialize(&Sig::Value { val: func, at: ty }),
332                                &mut self.0.ctx,
333                                pol,
334                            );
335                        } else {
336                            // todo: general select operator
337                        }
338                    }
339                    Value::Array(..) => self.array_method(ty, pol),
340                    _ => {}
341                }
342            }
343            Ty::Builtin(BuiltinTy::Element(elem)) => {
344                // todo: distinguish between element and function
345                if self.is_binder() {
346                    let func = (*elem).into();
347                    self.0.checker.check(
348                        Sig::Partialize(&Sig::Value { val: &func, at: ty }),
349                        &mut self.0.ctx,
350                        pol,
351                    );
352                } else {
353                    // todo: general select operator
354                }
355            }
356            Ty::Func(sig) => {
357                if self.is_binder() {
358                    self.0
359                        .checker
360                        .check(Sig::Partialize(&Sig::Type(sig)), &mut self.0.ctx, pol);
361                } else {
362                    // todo: general select operator
363                }
364            }
365            Ty::With(w) => {
366                self.0.ctx.args.push(w.with.clone());
367                w.sig.bounds(pol, self);
368                self.0.ctx.args.pop();
369            }
370            Ty::Tuple(..) => self.array_method(ty, pol),
371            Ty::Array(..) => self.array_method(ty, pol),
372            // todo: general select operator
373            _ => {}
374        }
375    }
376}