1use typst::foundations::{Func, Value};
2
3use super::BoundChecker;
4use crate::ty::prelude::*;
5
6#[derive(Debug, Clone, Copy)]
8pub enum Sig<'a> {
9 Builtin(BuiltinSig<'a>),
11 Type(&'a Interned<SigTy>),
13 TypeCons {
15 val: &'a typst::foundations::Type,
17 at: &'a Ty,
19 },
20 ArrayCons(&'a TyRef),
22 TupleCons(&'a Interned<Vec<Ty>>),
24 DictCons(&'a Interned<RecordTy>),
26 Value {
28 val: &'a Func,
30 at: &'a Ty,
32 },
33 Partialize(&'a Sig<'a>),
35 With {
37 sig: &'a Sig<'a>,
39 withs: &'a Vec<Interned<ArgsTy>>,
41 at: &'a Ty,
43 },
44}
45
46pub struct SigShape<'a> {
48 pub sig: Interned<SigTy>,
50 pub withs: Option<&'a Vec<Interned<SigTy>>>,
52}
53
54impl<'a> Sig<'a> {
55 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 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 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
101pub enum SigSurfaceKind {
102 Call,
104 Array,
106 Dict,
108 ArrayOrDict,
110}
111
112pub trait SigChecker: TyCtx {
114 fn check(&mut self, sig: Sig, args: &mut SigCheckContext, pol: bool) -> Option<()>;
116}
117
118impl Ty {
119 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 pub fn sig_repr(&self, pol: bool, ctx: &mut impl TyCtxMut) -> Option<Interned<SigTy>> {
132 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 &mut SigReprDriver(ctx, &mut primary),
157 );
158
159 primary
160 }
161}
162
163pub struct SigCheckContext {
165 pub sig_kind: SigSurfaceKind,
167 pub args: Vec<Interned<SigTy>>,
169 pub at: TyRef,
171}
172
173#[derive(BindTyCtx)]
175#[bind(checker)]
176pub struct SigCheckDriver<'a> {
177 ctx: SigCheckContext,
178 checker: &'a mut dyn SigChecker,
179}
180
181impl SigCheckDriver<'_> {
182 fn func_as_sig(&self) -> bool {
184 matches!(self.ctx.sig_kind, SigSurfaceKind::Call)
185 }
186
187 fn array_as_sig(&self) -> bool {
189 matches!(
190 self.ctx.sig_kind,
191 SigSurfaceKind::Array | SigSurfaceKind::ArrayOrDict
192 )
193 }
194
195 fn dict_as_sig(&self) -> bool {
197 matches!(
198 self.ctx.sig_kind,
199 SigSurfaceKind::Dict | SigSurfaceKind::ArrayOrDict
200 )
201 }
202
203 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 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 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 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.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 Ty::Unary(_) => {}
280 Ty::Binary(_) => {}
281 Ty::If(_) => {}
282 Ty::Param(param) => {
283 self.ty(¶m.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#[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 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 }
338 }
339 Value::Array(..) => self.array_method(ty, pol),
340 _ => {}
341 }
342 }
343 Ty::Builtin(BuiltinTy::Element(elem)) => {
344 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 }
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 }
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 _ => {}
374 }
375 }
376}