tinymist_analysis/ty/
apply.rs

1use std::sync::LazyLock;
2
3use super::{Sig, SigChecker, SigSurfaceKind, TyCtx};
4use crate::ty::prelude::*;
5
6/// A trait for checking the application of a signature.
7pub trait ApplyChecker: TyCtx {
8    /// Applies a signature to the given arguments.
9    fn apply(&mut self, sig: Sig, arguments: &Interned<ArgsTy>, pol: bool);
10}
11
12/// The empty arguments type.
13static EMPTY_ARGS: LazyLock<Interned<ArgsTy>> = LazyLock::new(|| ArgsTy::default().into());
14
15impl Ty {
16    /// Calls the given type with the given arguments.
17    pub fn call(&self, args: &Interned<ArgsTy>, pol: bool, c: &mut impl ApplyChecker) {
18        ApplySigChecker(c, args).ty(self, SigSurfaceKind::Call, pol);
19    }
20
21    /// Gets the tuple element type of the given type.
22    pub fn tuple_element_of(&self, pol: bool, c: &mut impl ApplyChecker) {
23        ApplySigChecker(c, &EMPTY_ARGS).ty(self, SigSurfaceKind::Array, pol);
24    }
25
26    /// Get the element type of the given type.
27    pub fn element_of(&self, pol: bool, c: &mut impl ApplyChecker) {
28        ApplySigChecker(c, &EMPTY_ARGS).ty(self, SigSurfaceKind::ArrayOrDict, pol);
29    }
30}
31
32/// A checker for applying a signature to a type.
33#[derive(BindTyCtx)]
34#[bind(0)]
35pub struct ApplySigChecker<'a, T: ApplyChecker>(&'a mut T, &'a Interned<ArgsTy>);
36
37impl<T: ApplyChecker> ApplySigChecker<'_, T> {
38    /// Applies a signature to a type.
39    fn ty(&mut self, ty: &Ty, surface: SigSurfaceKind, pol: bool) {
40        ty.sig_surface(pol, surface, self)
41    }
42}
43
44impl<T: ApplyChecker> SigChecker for ApplySigChecker<'_, T> {
45    /// Checks a signature against a context.
46    fn check(&mut self, cano_sig: Sig, ctx: &mut super::SigCheckContext, pol: bool) -> Option<()> {
47        let (cano_sig, is_partialize) = match cano_sig {
48            Sig::Partialize(sig) => (*sig, true),
49            sig => (sig, false),
50        };
51        // Binds the arguments to the canonical signature.
52        let partial_sig = if ctx.args.is_empty() {
53            cano_sig
54        } else {
55            Sig::With {
56                sig: &cano_sig,
57                withs: &ctx.args,
58                at: &ctx.at,
59            }
60        };
61        let partial_sig = if is_partialize {
62            Sig::Partialize(&partial_sig)
63        } else {
64            partial_sig
65        };
66
67        self.0.apply(partial_sig, self.1, pol);
68        Some(())
69    }
70}