tinymist_analysis/ty/
subst.rs1use super::{Sig, SigShape, TyMutator};
2use crate::ty::prelude::*;
3
4impl Sig<'_> {
5 pub fn call(&self, args: &Interned<ArgsTy>, pol: bool, ctx: &mut impl TyCtxMut) -> Option<Ty> {
7 crate::log_debug_ct!("call {self:?} {args:?} {pol:?}");
8 ctx.with_scope(|ctx| {
9 let body = self.check_bind(args, ctx)?;
10
11 let mut checker = SubstituteChecker { ctx };
13 Some(checker.ty(&body, pol).unwrap_or(body))
14 })
15 }
16
17 pub fn check_bind(&self, args: &Interned<ArgsTy>, ctx: &mut impl TyCtxMut) -> Option<Ty> {
19 let SigShape { sig, withs } = self.shape(ctx)?;
20
21 for (arg_recv, arg_ins) in sig.matches(args, withs) {
25 if let Ty::Var(arg_recv) = arg_recv {
26 crate::log_debug_ct!("bind {arg_recv:?} {arg_ins:?}");
27 ctx.bind_local(arg_recv, arg_ins.clone());
28 }
29 }
30
31 sig.body.clone()
32 }
33}
34
35struct SubstituteChecker<'a, T: TyCtxMut> {
37 ctx: &'a mut T,
38}
39
40impl<T: TyCtxMut> SubstituteChecker<'_, T> {
41 fn ty(&mut self, body: &Ty, pol: bool) -> Option<Ty> {
43 body.mutate(pol, self)
44 }
45}
46
47impl<T: TyCtxMut> TyMutator for SubstituteChecker<'_, T> {
48 fn mutate(&mut self, ty: &Ty, pol: bool) -> Option<Ty> {
49 let _ = pol;
51
52 if let Ty::Var(v) = ty {
53 self.ctx.local_bind_of(v)
54 } else {
55 self.mutate_rec(ty, pol)
56 }
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use insta::{assert_debug_snapshot, assert_snapshot};
63 use tinymist_derive::BindTyCtx;
64
65 use super::{DynTypeBounds, Interned, Ty, TyCtx, TypeInfo, TypeVar};
66 use crate::ty::ApplyChecker;
67 use crate::ty::tests::*;
68 #[test]
69 fn test_ty() {
70 use super::*;
71 let ty = Ty::Builtin(BuiltinTy::Clause);
72 let ty_ref = TyRef::new(ty.clone());
73 assert_debug_snapshot!(ty_ref, @"Clause");
74 }
75
76 #[derive(Default, BindTyCtx)]
77 #[bind(0)]
78 struct CallCollector(TypeInfo, Vec<Ty>);
79
80 impl ApplyChecker for CallCollector {
81 fn apply(
82 &mut self,
83 sig: super::Sig,
84 arguments: &crate::adt::interner::Interned<super::ArgsTy>,
85 pol: bool,
86 ) {
87 let ty = sig.call(arguments, pol, &mut self.0);
88 if let Some(ty) = ty {
89 self.1.push(ty);
90 }
91 }
92 }
93
94 #[test]
95 fn test_sig_call() {
96 use super::*;
97
98 fn call(sig: Interned<SigTy>, args: Interned<SigTy>) -> String {
99 let sig_ty = Ty::Func(sig);
100 let mut collector = CallCollector::default();
101 sig_ty.call(&args, false, &mut collector);
102
103 collector.1.iter().fold(String::new(), |mut acc, ty| {
104 if !acc.is_empty() {
105 acc.push_str(", ");
106 }
107
108 acc.push_str(&format!("{ty:?}"));
109 acc
110 })
111 }
112
113 assert_snapshot!(call(literal_sig!(p1 -> p1), literal_args!(q1)), @"@q1");
114 assert_snapshot!(call(literal_sig!(!u1: w1 -> w1), literal_args!(!u1: w2)), @"@w2");
115 }
116}