tinymist_analysis/ty/
iface.rs

1use typst::foundations::{Dict, Func, Module, Scope, Type};
2use typst::syntax::FileId;
3
4use super::BoundChecker;
5use crate::{syntax::Decl, ty::prelude::*};
6
7/// A type that represents the interface of a type.
8#[derive(Debug, Clone, Copy)]
9pub enum Iface<'a> {
10    /// An array type.
11    Array(&'a Interned<Ty>),
12    /// A tuple type.
13    Tuple(&'a Interned<Vec<Ty>>),
14    /// A dictionary type.
15    Dict(&'a Interned<RecordTy>),
16    /// An arguments type.
17    Args {
18        /// The original type.
19        at: &'a Ty,
20    },
21    /// A content type.
22    Content {
23        /// The element type.
24        val: &'a typst::foundations::Element,
25        /// The original type.
26        at: &'a Ty,
27    },
28    /// A type type.
29    TypeType {
30        /// The type type.
31        val: &'a typst::foundations::Type,
32        /// The original type.
33        at: &'a Ty,
34    },
35    /// A type.
36    Type {
37        /// The type.
38        val: &'a typst::foundations::Type,
39        /// The original type.
40        at: &'a Ty,
41    },
42    /// A function type.
43    Func {
44        /// The function.
45        val: &'a typst::foundations::Func,
46        /// The original type.
47        at: &'a Ty,
48    },
49    /// A value type.
50    Value {
51        /// The value.
52        val: &'a Dict,
53        /// The original type.
54        at: &'a Ty,
55    },
56    /// A module type.
57    Module {
58        /// The module.
59        val: FileId,
60        /// The original type.
61        at: &'a Ty,
62    },
63    /// A module value type.
64    ModuleVal {
65        /// The module value.
66        val: &'a Module,
67        /// The original type.
68        at: &'a Ty,
69    },
70}
71
72impl Iface<'_> {
73    /// Converts the interface to a type.
74    pub fn to_type(self) -> Ty {
75        match self {
76            Iface::Array(ty) => Ty::Array(ty.clone()),
77            Iface::Tuple(tys) => Ty::Tuple(tys.clone()),
78            Iface::Dict(dict) => Ty::Dict(dict.clone()),
79            Iface::Args { at }
80            | Iface::Content { at, .. }
81            | Iface::TypeType { at, .. }
82            | Iface::Type { at, .. }
83            | Iface::Func { at, .. }
84            | Iface::Value { at, .. }
85            | Iface::Module { at, .. }
86            | Iface::ModuleVal { at, .. } => at.clone(),
87        }
88    }
89
90    /// Selects the given key from the interface.
91    pub fn select(self, ctx: &mut impl TyCtxMut, key: &StrRef) -> Option<Ty> {
92        crate::log_debug_ct!("iface shape: {self:?}");
93
94        match self {
95            Iface::Array(..) | Iface::Tuple(..) => {
96                select_scope(Some(Type::of::<typst::foundations::Array>().scope()), key)
97            }
98            Iface::Dict(dict) => dict.field_by_name(key).cloned(),
99            Iface::Args { at } => {
100                if BuiltinSig::arguments_method(at, key).is_some() {
101                    return None;
102                }
103                select_scope(Some(Type::of::<typst::foundations::Args>().scope()), key)
104            }
105            Iface::Content { val, .. } => select_scope(Some(val.scope()), key),
106            // todo: distinguish TypeType and Type
107            Iface::TypeType { val, .. } | Iface::Type { val, .. } => {
108                select_scope(Some(val.scope()), key)
109            }
110            Iface::Func { val, .. } => select_scope(val.scope(), key),
111            Iface::Value { val, at: _ } => ctx.type_of_dict(val).field_by_name(key).cloned(),
112            Iface::Module { val, at: _ } => ctx.check_module_item(val, key),
113            Iface::ModuleVal { val, at: _ } => ctx.type_of_module(val).field_by_name(key).cloned(),
114        }
115    }
116}
117
118/// Selects the given key from the given scope.
119fn select_scope(scope: Option<&Scope>, key: &str) -> Option<Ty> {
120    let scope = scope?;
121    let sub = scope.get(key)?;
122    let sub_span = sub.span();
123    Some(Ty::Value(InsTy::new_at(sub.read().clone(), sub_span)))
124}
125
126/// A trait to check the interface of a type.
127pub trait IfaceChecker: TyCtx {
128    /// Checks the interface of the given type.
129    fn check(&mut self, iface: Iface, ctx: &mut IfaceCheckContext, pol: bool) -> Option<()>;
130}
131
132impl Ty {
133    /// Iterates over the signatures of the given type.
134    pub fn iface_surface(
135        &self,
136        pol: bool,
137        // iface_kind: IfaceSurfaceKind,
138        checker: &mut impl IfaceChecker,
139    ) {
140        let context = IfaceCheckContext { args: Vec::new() };
141        let mut worker = IfaceCheckDriver {
142            ctx: context,
143            checker,
144        };
145
146        worker.ty(self, pol);
147    }
148}
149
150/// A context to check the interface of a type.
151pub struct IfaceCheckContext {
152    /// The arguments of the function.
153    pub args: Vec<Interned<SigTy>>,
154}
155
156/// A driver to check the interface of a type.
157#[derive(BindTyCtx)]
158#[bind(checker)]
159pub struct IfaceCheckDriver<'a> {
160    ctx: IfaceCheckContext,
161    checker: &'a mut dyn IfaceChecker,
162}
163
164impl BoundChecker for IfaceCheckDriver<'_> {
165    fn collect(&mut self, ty: &Ty, pol: bool) {
166        self.ty(ty, pol);
167    }
168}
169
170impl IfaceCheckDriver<'_> {
171    /// Determines whether to check the array as an interface.
172    fn array_as_iface(&self) -> bool {
173        true
174    }
175
176    /// Determines whether to check the dictionary as an interface.
177    fn dict_as_iface(&self) -> bool {
178        true
179    }
180
181    /// Determines whether to check the value as an interface.
182    fn value_as_iface(&self) -> bool {
183        true
184    }
185
186    /// Checks the interface of the given type.
187    fn ty(&mut self, at: &Ty, pol: bool) {
188        crate::log_debug_ct!("check iface ty: {at:?}");
189
190        match at {
191            Ty::Builtin(BuiltinTy::Stroke) if self.dict_as_iface() => {
192                self.checker
193                    .check(Iface::Dict(&FLOW_STROKE_DICT), &mut self.ctx, pol);
194            }
195            Ty::Builtin(BuiltinTy::Margin) if self.dict_as_iface() => {
196                self.checker
197                    .check(Iface::Dict(&FLOW_MARGIN_DICT), &mut self.ctx, pol);
198            }
199            Ty::Builtin(BuiltinTy::Inset) if self.dict_as_iface() => {
200                self.checker
201                    .check(Iface::Dict(&FLOW_INSET_DICT), &mut self.ctx, pol);
202            }
203            Ty::Builtin(BuiltinTy::Outset) if self.dict_as_iface() => {
204                self.checker
205                    .check(Iface::Dict(&FLOW_OUTSET_DICT), &mut self.ctx, pol);
206            }
207            Ty::Builtin(BuiltinTy::Radius) if self.dict_as_iface() => {
208                self.checker
209                    .check(Iface::Dict(&FLOW_RADIUS_DICT), &mut self.ctx, pol);
210            }
211            Ty::Builtin(BuiltinTy::TextFont) if self.dict_as_iface() => {
212                self.checker
213                    .check(Iface::Dict(&FLOW_TEXT_FONT_DICT), &mut self.ctx, pol);
214            }
215            Ty::Builtin(BuiltinTy::Args) => {
216                self.checker.check(Iface::Args { at }, &mut self.ctx, pol);
217            }
218            Ty::Value(ins_ty) => {
219                // todo: deduplicate checking early
220                if self.value_as_iface() {
221                    match &ins_ty.val {
222                        Value::Module(val) => {
223                            self.checker
224                                .check(Iface::ModuleVal { val, at }, &mut self.ctx, pol);
225                        }
226                        Value::Dict(dict) => {
227                            self.checker
228                                .check(Iface::Value { val: dict, at }, &mut self.ctx, pol);
229                        }
230                        Value::Type(ty) => {
231                            self.checker
232                                .check(Iface::TypeType { val: ty, at }, &mut self.ctx, pol);
233                        }
234                        Value::Func(func) => {
235                            self.checker
236                                .check(Iface::Func { val: func, at }, &mut self.ctx, pol);
237                        }
238                        Value::Args(..) => {
239                            self.checker.check(Iface::Args { at }, &mut self.ctx, pol);
240                        }
241                        Value::None
242                        | Value::Auto
243                        | Value::Bool(_)
244                        | Value::Int(_)
245                        | Value::Float(_)
246                        | Value::Length(..)
247                        | Value::Angle(..)
248                        | Value::Ratio(..)
249                        | Value::Relative(..)
250                        | Value::Fraction(..)
251                        | Value::Color(..)
252                        | Value::Gradient(..)
253                        | Value::Tiling(..)
254                        | Value::Symbol(..)
255                        | Value::Version(..)
256                        | Value::Str(..)
257                        | Value::Bytes(..)
258                        | Value::Label(..)
259                        | Value::Datetime(..)
260                        | Value::Decimal(..)
261                        | Value::Duration(..)
262                        | Value::Content(..)
263                        | Value::Styles(..)
264                        | Value::Array(..)
265                        | Value::Dyn(..) => {
266                            self.checker.check(
267                                Iface::Type {
268                                    val: &ins_ty.val.ty(),
269                                    at,
270                                },
271                                &mut self.ctx,
272                                pol,
273                            );
274                        }
275                    }
276                }
277            }
278            // todo: more builtin types to check
279            Ty::Builtin(BuiltinTy::Content(Some(elem))) if self.value_as_iface() => {
280                self.checker
281                    .check(Iface::Content { val: elem, at }, &mut self.ctx, pol);
282            }
283            Ty::Builtin(BuiltinTy::Content(..)) if self.value_as_iface() => {
284                let ty = Type::of::<typst::foundations::Content>();
285                self.checker
286                    .check(Iface::Type { val: &ty, at }, &mut self.ctx, pol);
287            }
288            Ty::Builtin(BuiltinTy::Type(ty)) if self.value_as_iface() => {
289                // todo: distinguish between element and function
290                self.checker
291                    .check(Iface::Type { val: ty, at }, &mut self.ctx, pol);
292            }
293            Ty::Builtin(BuiltinTy::Element(elem)) if self.value_as_iface() => {
294                self.checker.check(
295                    Iface::Func {
296                        val: &Func::from(*elem),
297                        at,
298                    },
299                    &mut self.ctx,
300                    pol,
301                );
302            }
303            Ty::Builtin(BuiltinTy::Module(module)) => {
304                if let Decl::Module(m) = module.as_ref() {
305                    self.checker
306                        .check(Iface::Module { val: m.fid, at }, &mut self.ctx, pol);
307                }
308            }
309            // Ty::Func(..) if self.value_as_iface() => {
310            //     self.checker.check(Iface::Type(sig), &mut self.ctx, pol);
311            // }
312            // Ty::Array(sig) if self.array_as_sig() => {
313            //     // let sig = FlowSignature::array_cons(*sig.clone(), true);
314            //     self.checker.check(Iface::ArrayCons(sig), &mut self.ctx, pol);
315            // }
316            // // todo: tuple
317            // Ty::Tuple(_) => {}
318            Ty::Dict(sig) if self.dict_as_iface() => {
319                // self.check_dict_signature(sig, pol, self.checker);
320                self.checker.check(Iface::Dict(sig), &mut self.ctx, pol);
321            }
322            Ty::Tuple(sig) if self.array_as_iface() => {
323                // self.check_dict_signature(sig, pol, self.checker);
324                self.checker.check(Iface::Tuple(sig), &mut self.ctx, pol);
325            }
326            Ty::Array(sig) if self.array_as_iface() => {
327                // self.check_dict_signature(sig, pol, self.checker);
328                self.checker.check(Iface::Array(sig), &mut self.ctx, pol);
329            }
330            Ty::Args(..) => {
331                self.checker.check(Iface::Args { at }, &mut self.ctx, pol);
332            }
333            Ty::Dict(..) => {
334                self.checker.check(
335                    Iface::Type {
336                        val: &Type::of::<typst::foundations::Dict>(),
337                        at,
338                    },
339                    &mut self.ctx,
340                    pol,
341                );
342            }
343            Ty::Tuple(..) | Ty::Array(..) => {
344                self.checker.check(
345                    Iface::Type {
346                        val: &Type::of::<typst::foundations::Array>(),
347                        at,
348                    },
349                    &mut self.ctx,
350                    pol,
351                );
352            }
353            Ty::Var(..) => at.bounds(pol, self),
354            _ if at.has_bounds() => at.bounds(pol, self),
355            _ => {}
356        }
357        // Ty::Select(sel) => sel.ty.bounds(pol, &mut MethodDriver(self,
358        // &sel.select)), // todo: calculate these operators
359        // Ty::Unary(_) => {}
360        // Ty::Binary(_) => {}
361        // Ty::If(_) => {}
362    }
363}