tinymist_analysis/ty/
apply.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use std::sync::LazyLock;

use super::{Sig, SigChecker, SigSurfaceKind, TyCtx};
use crate::ty::prelude::*;

pub trait ApplyChecker: TyCtx {
    fn apply(&mut self, sig: Sig, arguments: &Interned<ArgsTy>, pol: bool);
}

static EMPTY_ARGS: LazyLock<Interned<ArgsTy>> = LazyLock::new(|| ArgsTy::default().into());

impl Ty {
    /// Call the given type with the given arguments.
    pub fn call(&self, args: &Interned<ArgsTy>, pol: bool, c: &mut impl ApplyChecker) {
        ApplySigChecker(c, args).ty(self, SigSurfaceKind::Call, pol);
    }

    /// Get the tuple element type of the given type.
    pub fn tuple_element_of(&self, pol: bool, c: &mut impl ApplyChecker) {
        ApplySigChecker(c, &EMPTY_ARGS).ty(self, SigSurfaceKind::Array, pol);
    }

    /// Get the element type of the given type.
    pub fn element_of(&self, pol: bool, c: &mut impl ApplyChecker) {
        ApplySigChecker(c, &EMPTY_ARGS).ty(self, SigSurfaceKind::ArrayOrDict, pol);
    }
}

#[derive(BindTyCtx)]
#[bind(0)]
pub struct ApplySigChecker<'a, T: ApplyChecker>(&'a mut T, &'a Interned<ArgsTy>);

impl<T: ApplyChecker> ApplySigChecker<'_, T> {
    fn ty(&mut self, ty: &Ty, surface: SigSurfaceKind, pol: bool) {
        ty.sig_surface(pol, surface, self)
    }
}

impl<T: ApplyChecker> SigChecker for ApplySigChecker<'_, T> {
    fn check(&mut self, cano_sig: Sig, ctx: &mut super::SigCheckContext, pol: bool) -> Option<()> {
        let (cano_sig, is_partialize) = match cano_sig {
            Sig::Partialize(sig) => (*sig, true),
            sig => (sig, false),
        };
        // Bind the arguments to the canonical signature.
        let partial_sig = if ctx.args.is_empty() {
            cano_sig
        } else {
            Sig::With {
                sig: &cano_sig,
                withs: &ctx.args,
                at: &ctx.at,
            }
        };
        let partial_sig = if is_partialize {
            Sig::Partialize(&partial_sig)
        } else {
            partial_sig
        };

        self.0.apply(partial_sig, self.1, pol);
        Some(())
    }
}