tinymist_analysis/ty/
bound.rs1use std::ops::Deref;
2
3use typst::foundations::{self, Func};
4
5use crate::ty::prelude::*;
6
7pub trait BoundChecker: Sized + TyCtx {
9 fn collect(&mut self, ty: &Ty, pol: bool);
11
12 fn check_var(&mut self, u: &Interned<TypeVar>, pol: bool) {
14 self.check_var_rec(u, pol);
15 }
16
17 fn check_var_rec(&mut self, u: &Interned<TypeVar>, pol: bool) {
19 let Some(w) = self.global_bounds(u, pol) else {
20 return;
21 };
22 let mut ctx = BoundCheckContext;
23 ctx.tys(w.ubs.iter(), pol, self);
24 ctx.tys(w.lbs.iter(), !pol, self);
25 }
26}
27
28#[derive(BindTyCtx)]
30#[bind(0)]
31pub struct BoundPred<'a, T: TyCtx, F>(pub &'a T, pub F);
32
33impl<'a, T: TyCtx, F> BoundPred<'a, T, F> {
34 pub fn new(t: &'a T, f: F) -> Self {
36 Self(t, f)
37 }
38}
39
40impl<T: TyCtx, F> BoundChecker for BoundPred<'_, T, F>
41where
42 F: FnMut(&Ty, bool),
43{
44 fn collect(&mut self, ty: &Ty, pol: bool) {
45 self.1(ty, pol);
46 }
47}
48
49#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
51pub enum DocSource {
52 Var(Interned<TypeVar>),
54 Ins(Interned<InsTy>),
56 Builtin(BuiltinTy),
58}
59
60impl DocSource {
61 pub fn as_func(&self) -> Option<Func> {
63 match self {
64 Self::Var(..) => None,
65 Self::Builtin(BuiltinTy::Type(ty)) => Some(ty.constructor().ok()?),
66 Self::Builtin(BuiltinTy::Element(ty)) => Some((*ty).into()),
67 Self::Builtin(..) => None,
68 Self::Ins(ins_ty) => match &ins_ty.val {
69 foundations::Value::Func(func) => Some(func.clone()),
70 foundations::Value::Type(ty) => Some(ty.constructor().ok()?),
71 _ => None,
72 },
73 }
74 }
75}
76
77impl Ty {
78 pub fn has_bounds(&self) -> bool {
80 matches!(self, Ty::Union(_) | Ty::Let(_) | Ty::Var(_))
81 }
82
83 pub fn as_source(&self) -> Option<DocSource> {
85 match self {
86 Ty::Builtin(ty @ (BuiltinTy::Type(..) | BuiltinTy::Element(..))) => {
87 Some(DocSource::Builtin(ty.clone()))
88 }
89 Ty::Value(ty) => match &ty.val {
90 foundations::Value::Type(..) | foundations::Value::Func(..) => {
91 Some(DocSource::Ins(ty.clone()))
92 }
93 _ => None,
94 },
95 _ => None,
96 }
97 }
98
99 pub fn sources(&self) -> Vec<DocSource> {
101 let mut results = vec![];
102 fn collect(ty: &Ty, results: &mut Vec<DocSource>) {
103 use Ty::*;
104 if let Some(src) = ty.as_source() {
105 results.push(src);
106 return;
107 }
108 match ty {
109 Any | Boolean(_) | If(..) | Builtin(..) | Value(..) => {}
110 Dict(..) | Array(..) | Tuple(..) | Func(..) | Args(..) | Pattern(..) => {}
111 Unary(..) | Binary(..) => {}
112 Param(ty) => {
113 collect(&ty.ty, results);
115 }
116 Union(ty) => {
117 for ty in ty.iter() {
118 collect(ty, results);
119 }
120 }
121 Let(ty) => {
122 for ty in ty.ubs.iter() {
123 collect(ty, results);
124 }
125 for ty in ty.lbs.iter() {
126 collect(ty, results);
127 }
128 }
129 Var(ty) => {
130 results.push(DocSource::Var(ty.clone()));
131 }
132 With(ty) => collect(&ty.sig, results),
133 Select(ty) => {
134 if matches!(ty.select.deref(), "with" | "where") {
136 collect(&ty.ty, results);
137 }
138
139 }
141 }
142 }
143
144 collect(self, &mut results);
145 results
146 }
147
148 pub fn bounds(&self, pol: bool, checker: &mut impl BoundChecker) {
150 BoundCheckContext.ty(self, pol, checker);
151 }
152}
153
154pub struct BoundCheckContext;
156
157impl BoundCheckContext {
158 fn tys<'a>(&mut self, tys: impl Iterator<Item = &'a Ty>, pol: bool, c: &mut impl BoundChecker) {
160 for ty in tys {
161 self.ty(ty, pol, c);
162 }
163 }
164
165 fn ty(&mut self, ty: &Ty, pol: bool, checker: &mut impl BoundChecker) {
167 match ty {
168 Ty::Union(u) => {
169 self.tys(u.iter(), pol, checker);
170 }
171 Ty::Let(u) => {
172 self.tys(u.ubs.iter(), pol, checker);
173 self.tys(u.lbs.iter(), !pol, checker);
174 }
175 Ty::Var(u) => checker.check_var(u, pol),
176 ty => checker.collect(ty, pol),
182 }
183 }
184}