tinymist_analysis/ty/
mod.rs#![allow(missing_docs)]
mod apply;
mod bound;
mod builtin;
mod convert;
mod def;
mod describe;
mod iface;
mod mutate;
mod prelude;
mod select;
mod sig;
mod simplify;
mod subst;
pub use apply::*;
pub use bound::*;
pub use builtin::*;
pub use convert::*;
pub use def::*;
pub use iface::*;
pub use mutate::*;
pub use select::*;
pub use sig::*;
use typst::foundations::{self, Func, Module, Value};
use typst::syntax::FileId;
pub trait TyCtx {
fn local_bind_of(&self, _var: &Interned<TypeVar>) -> Option<Ty>;
fn global_bounds(&self, _var: &Interned<TypeVar>, _pol: bool) -> Option<DynTypeBounds>;
}
impl TyCtx for () {
fn local_bind_of(&self, _var: &Interned<TypeVar>) -> Option<Ty> {
None
}
fn global_bounds(&self, _var: &Interned<TypeVar>, _pol: bool) -> Option<DynTypeBounds> {
None
}
}
pub trait TyCtxMut: TyCtx {
type Snap;
#[must_use]
fn start_scope(&mut self) -> Self::Snap;
fn end_scope(&mut self, snap: Self::Snap);
fn with_scope<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
let snap = self.start_scope();
let res = f(self);
self.end_scope(snap);
res
}
fn bind_local(&mut self, var: &Interned<TypeVar>, ty: Ty);
fn type_of_func(&mut self, func: &Func) -> Option<Interned<SigTy>>;
fn type_of_value(&mut self, val: &Value) -> Ty;
fn type_of_dict(&mut self, dict: &foundations::Dict) -> Interned<RecordTy> {
let ty = self.type_of_value(&Value::Dict(dict.clone()));
let Ty::Dict(ty) = ty else {
panic!("expected dict type, found {ty:?}");
};
ty
}
fn type_of_module(&mut self, module: &Module) -> Interned<RecordTy> {
let ty = self.type_of_value(&Value::Module(module.clone()));
let Ty::Dict(ty) = ty else {
panic!("expected dict type, found {ty:?}");
};
ty
}
fn check_module_item(&mut self, module: FileId, key: &StrRef) -> Option<Ty>;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::adt::interner::Interned;
use crate::syntax::Decl;
pub fn var_ins(s: &str) -> Ty {
Ty::Var(TypeVar::new(s.into(), Decl::lit(s).into()))
}
pub fn str_sig(
pos: &[&str],
named: &[(&str, &str)],
rest: Option<&str>,
ret: Option<&str>,
) -> Interned<SigTy> {
let pos = pos.iter().map(|s| var_ins(s));
let named = named.iter().map(|(n, t)| ((*n).into(), var_ins(t)));
let rest = rest.map(var_ins);
let ret = ret.map(var_ins);
SigTy::new(pos, named, None, rest, ret).into()
}
macro_rules! literal_sig {
($($pos:ident),* $(!$named:ident: $named_ty:ident),* $(,)? ...$rest:ident -> $ret:ident) => {
str_sig(&[$(stringify!($pos)),*], &[$((stringify!($named), stringify!($named_ty))),*], Some(stringify!($rest)), Some(stringify!($ret)))
};
($($pos:ident),* $(!$named:ident: $named_ty:ident),* $(,)? -> $ret:ident) => {
str_sig(&[$(stringify!($pos)),*], &[$((stringify!($named), stringify!($named_ty))),*], None, Some(stringify!($ret)))
};
($($pos:ident),* $(!$named:ident: $named_ty:ident),* $(,)? ...$rest:ident) => {
str_sig(&[$(stringify!($pos)),*], &[$((stringify!($named), stringify!($named_ty))),*], Some(stringify!($rest)), None)
};
($($pos:ident),* $(!$named:ident: $named_ty:ident),* $(,)?) => {
str_sig(&[$(stringify!($pos)),*], &[$((stringify!($named), stringify!($named_ty))),*], None, None)
};
}
pub(crate) use literal_sig;
pub(crate) use literal_sig as literal_args;
}