mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-07-23 04:35:00 +00:00
docs: add documents to type system (#295)
* docs: simplify a bit * docs: add documents to type system code * docs: update * refactor: rename
This commit is contained in:
parent
c182c5fadc
commit
9835ffe6ab
17 changed files with 969 additions and 819 deletions
|
@ -34,7 +34,7 @@ mod type_check_tests {
|
|||
use crate::analysis::ty;
|
||||
use crate::tests::*;
|
||||
|
||||
use super::{Ty, TypeCheckInfo};
|
||||
use super::{Ty, TypeScheme};
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
|
@ -51,7 +51,7 @@ mod type_check_tests {
|
|||
});
|
||||
}
|
||||
|
||||
struct TypeCheckSnapshot<'a>(&'a Source, &'a TypeCheckInfo);
|
||||
struct TypeCheckSnapshot<'a>(&'a Source, &'a TypeScheme);
|
||||
|
||||
impl fmt::Debug for TypeCheckSnapshot<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
|
|
@ -26,7 +26,7 @@ use typst::{layout::Position, syntax::FileId as TypstFileId};
|
|||
|
||||
use super::{
|
||||
analyze_bib, post_type_check, BibInfo, DefUseInfo, DefinitionLink, IdentRef, ImportInfo,
|
||||
PathPreference, SigTy, Signature, SignatureTarget, Ty, TypeCheckInfo,
|
||||
PathPreference, SigTy, Signature, SignatureTarget, Ty, TypeScheme,
|
||||
};
|
||||
use crate::adt::interner::Interned;
|
||||
use crate::analysis::analyze_dyn_signature;
|
||||
|
@ -49,7 +49,7 @@ pub struct ModuleAnalysisCache {
|
|||
source: OnceCell<FileResult<Source>>,
|
||||
import_info: OnceCell<Option<Arc<ImportInfo>>>,
|
||||
def_use: OnceCell<Option<Arc<DefUseInfo>>>,
|
||||
type_check: OnceCell<Option<Arc<TypeCheckInfo>>>,
|
||||
type_check: OnceCell<Option<Arc<TypeScheme>>>,
|
||||
bibliography: OnceCell<Option<Arc<BibInfo>>>,
|
||||
}
|
||||
|
||||
|
@ -93,15 +93,15 @@ impl ModuleAnalysisCache {
|
|||
}
|
||||
|
||||
/// Try to get the type check information of a file.
|
||||
pub(crate) fn type_check(&self) -> Option<Arc<TypeCheckInfo>> {
|
||||
pub(crate) fn type_check(&self) -> Option<Arc<TypeScheme>> {
|
||||
self.type_check.get().cloned().flatten()
|
||||
}
|
||||
|
||||
/// Compute the type check information of a file.
|
||||
pub(crate) fn compute_type_check(
|
||||
&self,
|
||||
f: impl FnOnce() -> Option<Arc<TypeCheckInfo>>,
|
||||
) -> Option<Arc<TypeCheckInfo>> {
|
||||
f: impl FnOnce() -> Option<Arc<TypeScheme>>,
|
||||
) -> Option<Arc<TypeScheme>> {
|
||||
self.type_check.get_or_init(f).clone()
|
||||
}
|
||||
|
||||
|
@ -308,7 +308,7 @@ impl<Inputs, Output> ComputingNode<Inputs, Output> {
|
|||
#[allow(clippy::type_complexity)]
|
||||
pub struct ModuleAnalysisGlobalCache {
|
||||
def_use_lexical_hierarchy: ComputingNode<Source, EcoVec<LexicalHierarchy>>,
|
||||
type_check: Arc<ComputingNode<Source, Arc<TypeCheckInfo>>>,
|
||||
type_check: Arc<ComputingNode<Source, Arc<TypeScheme>>>,
|
||||
def_use: Arc<ComputingNode<(EcoVec<LexicalHierarchy>, Arc<ImportInfo>), Arc<DefUseInfo>>>,
|
||||
|
||||
bibliography: Arc<ComputingNode<EcoVec<(TypstFileId, Bytes)>, Arc<BibInfo>>>,
|
||||
|
@ -670,7 +670,7 @@ impl<'w> AnalysisContext<'w> {
|
|||
}
|
||||
|
||||
/// Get the type check information of a source file.
|
||||
pub(crate) fn type_check(&mut self, source: Source) -> Option<Arc<TypeCheckInfo>> {
|
||||
pub(crate) fn type_check(&mut self, source: Source) -> Option<Arc<TypeScheme>> {
|
||||
let fid = source.id();
|
||||
|
||||
if let Some(res) = self.caches.modules.entry(fid).or_default().type_check() {
|
||||
|
|
|
@ -13,7 +13,7 @@ use typst::{
|
|||
};
|
||||
|
||||
use crate::analysis::{Ty, *};
|
||||
use crate::{analysis::TypeCheckInfo, ty::TypeInterace, AnalysisContext};
|
||||
use crate::{analysis::TypeScheme, ty::TypeInterface, AnalysisContext};
|
||||
|
||||
use super::{
|
||||
resolve_global_value, BuiltinTy, DefUseInfo, FlowVarKind, IdentRef, TypeBounds, TypeVar,
|
||||
|
@ -28,8 +28,8 @@ pub(crate) use apply::*;
|
|||
pub(crate) use post_check::*;
|
||||
|
||||
/// Type checking at the source unit level.
|
||||
pub(crate) fn type_check(ctx: &mut AnalysisContext, source: Source) -> Option<Arc<TypeCheckInfo>> {
|
||||
let mut info = TypeCheckInfo::default();
|
||||
pub(crate) fn type_check(ctx: &mut AnalysisContext, source: Source) -> Option<Arc<TypeScheme>> {
|
||||
let mut info = TypeScheme::default();
|
||||
|
||||
// Retrieve def-use information for the source.
|
||||
let def_use_info = ctx.def_use(source.clone())?;
|
||||
|
@ -64,7 +64,7 @@ struct TypeChecker<'a, 'w> {
|
|||
source: Source,
|
||||
def_use_info: Arc<DefUseInfo>,
|
||||
|
||||
info: &'a mut TypeCheckInfo,
|
||||
info: &'a mut TypeScheme,
|
||||
externals: HashMap<DefId, Option<Ty>>,
|
||||
mode: InterpretMode,
|
||||
}
|
||||
|
@ -98,7 +98,6 @@ impl<'a, 'w> TypeChecker<'a, 'w> {
|
|||
TypeVar {
|
||||
name: r.name.as_str().into(),
|
||||
def: def_id,
|
||||
syntax: None,
|
||||
},
|
||||
init_expr,
|
||||
),
|
||||
|
@ -106,7 +105,7 @@ impl<'a, 'w> TypeChecker<'a, 'w> {
|
|||
}
|
||||
|
||||
let var = self.info.vars.get_mut(&def_id).unwrap();
|
||||
TypeCheckInfo::witness_(s, var.as_type(), &mut self.info.mapping);
|
||||
TypeScheme::witness_(s, var.as_type(), &mut self.info.mapping);
|
||||
Some(var.as_type())
|
||||
}
|
||||
|
||||
|
@ -250,7 +249,7 @@ impl<'a, 'w> TypeChecker<'a, 'w> {
|
|||
}
|
||||
}
|
||||
(Ty::Dict(lhs), Ty::Dict(rhs)) => {
|
||||
for (key, lhs, rhs) in lhs.intersect_keys(rhs) {
|
||||
for (key, lhs, rhs) in lhs.common_iface_fields(rhs) {
|
||||
log::debug!("constrain record item {key} {lhs:?} ⪯ {rhs:?}");
|
||||
self.constrain(lhs, rhs);
|
||||
// if !sl.is_detached() {
|
||||
|
@ -280,7 +279,7 @@ impl<'a, 'w> TypeChecker<'a, 'w> {
|
|||
}
|
||||
(Ty::Value(lhs), rhs) => {
|
||||
log::debug!("constrain value {lhs:?} ⪯ {rhs:?}");
|
||||
let _ = TypeCheckInfo::witness_at_most;
|
||||
let _ = TypeScheme::witness_at_most;
|
||||
// if !lhs.1.is_detached() {
|
||||
// self.info.witness_at_most(lhs.1, rhs.clone());
|
||||
// }
|
||||
|
@ -402,7 +401,7 @@ impl<'a, 'w> TypeChecker<'a, 'w> {
|
|||
self.weaken(&v.lhs);
|
||||
}
|
||||
Ty::Binary(v) => {
|
||||
let (lhs, rhs) = v.repr();
|
||||
let [lhs, rhs] = v.operands();
|
||||
self.weaken(lhs);
|
||||
self.weaken(rhs);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ impl<'a, 'b, 'w> ApplyChecker for ApplyTypeChecker<'a, 'b, 'w> {
|
|||
.map(|v| v.bounds.bounds().read().clone())
|
||||
}
|
||||
|
||||
fn call(&mut self, sig: Sig, args: &Interned<ArgsTy>, pol: bool) {
|
||||
fn apply(&mut self, sig: Sig, args: &Interned<ArgsTy>, pol: bool) {
|
||||
let _ = self.args;
|
||||
|
||||
let (sig, is_partialize) = match sig {
|
||||
|
|
|
@ -15,13 +15,13 @@ use crate::{
|
|||
AnalysisContext,
|
||||
};
|
||||
|
||||
use super::{FieldTy, SigShape, Ty, TypeCheckInfo};
|
||||
use super::{FieldTy, SigShape, Ty, TypeScheme};
|
||||
|
||||
/// With given type information, check the type of a literal expression again by
|
||||
/// touching the possible related nodes.
|
||||
pub(crate) fn post_type_check(
|
||||
_ctx: &mut AnalysisContext,
|
||||
info: &TypeCheckInfo,
|
||||
info: &TypeScheme,
|
||||
node: LinkedNode,
|
||||
) -> Option<Ty> {
|
||||
let mut worker = PostTypeCheckWorker {
|
||||
|
@ -108,7 +108,7 @@ fn check_signature<'a>(
|
|||
struct PostTypeCheckWorker<'a, 'w> {
|
||||
ctx: &'a mut AnalysisContext<'w>,
|
||||
checked: HashMap<Span, Option<Ty>>,
|
||||
info: &'a TypeCheckInfo,
|
||||
info: &'a TypeScheme,
|
||||
}
|
||||
|
||||
impl<'a, 'w> PostTypeCheckWorker<'a, 'w> {
|
||||
|
|
|
@ -143,7 +143,7 @@ impl SemanticRequest for SignatureHelpRequest {
|
|||
label.push(')');
|
||||
let ret = type_sig
|
||||
.as_ref()
|
||||
.and_then(|sig| sig.ret.as_ref())
|
||||
.and_then(|sig| sig.body.as_ref())
|
||||
.or_else(|| sig.primary().ret_ty.as_ref());
|
||||
if let Some(ret_ty) = ret {
|
||||
label.push_str(" -> ");
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{adt::interner::Interned, ty::def::*};
|
|||
use super::{Sig, SigChecker, SigSurfaceKind};
|
||||
|
||||
pub trait ApplyChecker {
|
||||
fn call(&mut self, sig: Sig, arguments: &Interned<ArgsTy>, pol: bool);
|
||||
fn apply(&mut self, sig: Sig, arguments: &Interned<ArgsTy>, pol: bool);
|
||||
|
||||
fn bound_of_var(&mut self, _var: &Interned<TypeVar>, _pol: bool) -> Option<TypeBounds> {
|
||||
None
|
||||
|
@ -13,11 +13,12 @@ pub trait ApplyChecker {
|
|||
}
|
||||
|
||||
impl Ty {
|
||||
/// Call the given type with the given arguments.
|
||||
pub fn call(&self, args: &Interned<ArgsTy>, pol: bool, checker: &mut impl ApplyChecker) {
|
||||
self.apply(SigSurfaceKind::Call, args, pol, checker)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
/// Get the element type of the given type.
|
||||
pub fn element_of(&self, pol: bool, checker: &mut impl ApplyChecker) {
|
||||
static EMPTY_ARGS: Lazy<Interned<ArgsTy>> = Lazy::new(|| ArgsTy::default().into());
|
||||
|
||||
|
@ -46,18 +47,17 @@ impl<'a, T: ApplyChecker> ApplySigChecker<'a, T> {
|
|||
|
||||
impl<'a, T: ApplyChecker> SigChecker for ApplySigChecker<'a, T> {
|
||||
fn check(&mut self, cano_sig: Sig, ctx: &mut super::SigCheckContext, pol: bool) -> Option<()> {
|
||||
let args = &ctx.args;
|
||||
let partial_sig = if args.is_empty() {
|
||||
// Bind the arguments to the canonical signature.
|
||||
let partial_sig = if ctx.args.is_empty() {
|
||||
cano_sig
|
||||
} else {
|
||||
Sig::With {
|
||||
sig: &cano_sig,
|
||||
withs: args,
|
||||
withs: &ctx.args,
|
||||
at: &ctx.at,
|
||||
}
|
||||
};
|
||||
|
||||
self.0.call(partial_sig, self.1, pol);
|
||||
self.0.apply(partial_sig, self.1, pol);
|
||||
Some(())
|
||||
}
|
||||
|
||||
|
|
|
@ -17,10 +17,12 @@ where
|
|||
}
|
||||
|
||||
impl Ty {
|
||||
/// Check if the given type has bounds (is combinated).
|
||||
pub fn has_bounds(&self) -> bool {
|
||||
matches!(self, Ty::Union(_) | Ty::Let(_) | Ty::Var(_))
|
||||
}
|
||||
|
||||
/// Profile the bounds of the given type.
|
||||
pub fn bounds(&self, pol: bool, checker: &mut impl BoundChecker) {
|
||||
let mut worker = BoundCheckContext;
|
||||
worker.ty(self, pol, checker);
|
||||
|
|
|
@ -11,7 +11,7 @@ use typst::{
|
|||
use crate::{adt::interner::Interned, ty::*};
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub(crate) enum PathPreference {
|
||||
pub enum PathPreference {
|
||||
None,
|
||||
Special,
|
||||
Source,
|
||||
|
@ -84,7 +84,7 @@ impl PathPreference {
|
|||
}
|
||||
|
||||
impl Ty {
|
||||
pub fn from_return_site(f: &Func, c: &'_ CastInfo) -> Option<Self> {
|
||||
pub(crate) fn from_return_site(f: &Func, c: &'_ CastInfo) -> Option<Self> {
|
||||
use typst::foundations::func::Repr;
|
||||
match f.inner() {
|
||||
Repr::Element(e) => return Some(Ty::Builtin(BuiltinTy::Element(*e))),
|
||||
|
@ -95,7 +95,7 @@ impl Ty {
|
|||
|
||||
let ty = match c {
|
||||
CastInfo::Any => Ty::Any,
|
||||
CastInfo::Value(v, doc) => Ty::Value(InsTy::new_doc(v.clone(), doc)),
|
||||
CastInfo::Value(v, doc) => Ty::Value(InsTy::new_doc(v.clone(), *doc)),
|
||||
CastInfo::Type(ty) => Ty::Builtin(BuiltinTy::Type(*ty)),
|
||||
CastInfo::Union(e) => {
|
||||
// flat union
|
||||
|
@ -122,7 +122,7 @@ impl Ty {
|
|||
|
||||
let ty = match &s {
|
||||
CastInfo::Any => Ty::Any,
|
||||
CastInfo::Value(v, doc) => Ty::Value(InsTy::new_doc(v.clone(), doc)),
|
||||
CastInfo::Value(v, doc) => Ty::Value(InsTy::new_doc(v.clone(), *doc)),
|
||||
CastInfo::Type(ty) => Ty::Builtin(BuiltinTy::Type(*ty)),
|
||||
CastInfo::Union(e) => {
|
||||
// flat union
|
||||
|
@ -159,7 +159,7 @@ impl<'a> Iterator for UnionIter<'a> {
|
|||
}
|
||||
|
||||
#[derive(Clone, Hash, PartialEq, Eq)]
|
||||
pub(crate) enum BuiltinTy {
|
||||
pub enum BuiltinTy {
|
||||
Clause,
|
||||
Undef,
|
||||
Content,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,7 +5,8 @@ use typst::foundations::Repr;
|
|||
|
||||
use crate::{adt::interner::Interned, analysis::*, ty::def::*};
|
||||
|
||||
impl TypeCheckInfo {
|
||||
impl TypeScheme {
|
||||
/// Describe the given type with the given type scheme.
|
||||
pub fn describe(&self, ty: &Ty) -> Option<String> {
|
||||
let mut worker = TypeDescriber::default();
|
||||
worker.describe_root(ty)
|
||||
|
@ -13,6 +14,7 @@ impl TypeCheckInfo {
|
|||
}
|
||||
|
||||
impl Ty {
|
||||
/// Describe the given type.
|
||||
pub fn describe(&self) -> Option<String> {
|
||||
let mut worker = TypeDescriber::default();
|
||||
worker.describe_root(self)
|
||||
|
@ -80,7 +82,7 @@ impl TypeDescriber {
|
|||
}
|
||||
res.push_str(") => ");
|
||||
res.push_str(
|
||||
f.ret
|
||||
f.body
|
||||
.as_ref()
|
||||
.and_then(|ret| self.describe_root(ret))
|
||||
.as_deref()
|
||||
|
|
|
@ -13,7 +13,7 @@ mod subst;
|
|||
pub(crate) use apply::*;
|
||||
pub(crate) use bound::*;
|
||||
pub(crate) use builtin::*;
|
||||
pub(crate) use def::*;
|
||||
pub use def::*;
|
||||
pub(crate) use mutate::*;
|
||||
pub(crate) use sig::*;
|
||||
|
||||
|
|
|
@ -32,17 +32,21 @@ pub trait MutateDriver {
|
|||
}
|
||||
|
||||
fn mutate_func(&mut self, ty: &Interned<SigTy>, pol: bool) -> Option<SigTy> {
|
||||
let types = self.mutate_vec(&ty.types, pol);
|
||||
let ret = self.mutate_option(ty.ret.as_ref(), pol);
|
||||
let types = self.mutate_vec(&ty.inputs, pol);
|
||||
let ret = self.mutate_option(ty.body.as_ref(), pol);
|
||||
|
||||
if types.is_none() && ret.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let sig = ty.as_ref().clone();
|
||||
let types = types.unwrap_or_else(|| ty.types.clone());
|
||||
let ret = ret.unwrap_or_else(|| ty.ret.clone());
|
||||
Some(SigTy { types, ret, ..sig })
|
||||
let types = types.unwrap_or_else(|| ty.inputs.clone());
|
||||
let ret = ret.unwrap_or_else(|| ty.body.clone());
|
||||
Some(SigTy {
|
||||
inputs: types,
|
||||
body: ret,
|
||||
..sig
|
||||
})
|
||||
}
|
||||
|
||||
fn mutate_record(&mut self, ty: &Interned<RecordTy>, pol: bool) -> Option<RecordTy> {
|
||||
|
@ -127,6 +131,7 @@ where
|
|||
}
|
||||
|
||||
impl Ty {
|
||||
/// Mutate the given type.
|
||||
pub fn mutate(&self, pol: bool, checker: &mut impl MutateDriver) -> Option<Ty> {
|
||||
let mut worker = Mutator;
|
||||
worker.ty(self, pol, checker)
|
||||
|
|
|
@ -90,6 +90,7 @@ where
|
|||
}
|
||||
|
||||
impl Ty {
|
||||
/// Iterate over the signatures of the given type.
|
||||
pub fn sig_surface(&self, pol: bool, sig_kind: SigSurfaceKind, checker: &mut impl SigChecker) {
|
||||
let context = SigCheckContext {
|
||||
sig_kind,
|
||||
|
@ -104,6 +105,7 @@ impl Ty {
|
|||
worker.ty(self, pol);
|
||||
}
|
||||
|
||||
/// Get the signature representation of the given type.
|
||||
pub fn sig_repr(&self, pol: bool) -> Option<Interned<SigTy>> {
|
||||
// todo: union sig
|
||||
// let mut pos = vec![];
|
||||
|
@ -248,7 +250,7 @@ impl BoundChecker for SigCheckDriver<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
struct MethodDriver<'a, 'b>(&'a mut SigCheckDriver<'b>, &'a Interned<str>);
|
||||
struct MethodDriver<'a, 'b>(&'a mut SigCheckDriver<'b>, &'a StrRef);
|
||||
|
||||
impl<'a, 'b> MethodDriver<'a, 'b> {
|
||||
fn is_binder(&self) -> bool {
|
||||
|
|
|
@ -17,7 +17,8 @@ struct CompactTy {
|
|||
is_final: bool,
|
||||
}
|
||||
|
||||
impl TypeCheckInfo {
|
||||
impl TypeScheme {
|
||||
/// Simplify (Canonicalize) the given type with the given type scheme.
|
||||
pub fn simplify(&self, ty: Ty, principal: bool) -> Ty {
|
||||
let mut c = self.cano_cache.lock();
|
||||
let c = &mut *c;
|
||||
|
@ -94,7 +95,7 @@ impl<'a, 'b> TypeSimplifier<'a, 'b> {
|
|||
for p in f.inputs() {
|
||||
self.analyze(p, !pol);
|
||||
}
|
||||
if let Some(ret) = &f.ret {
|
||||
if let Some(ret) = &f.body {
|
||||
self.analyze(ret, pol);
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +125,7 @@ impl<'a, 'b> TypeSimplifier<'a, 'b> {
|
|||
}
|
||||
Ty::Unary(u) => self.analyze(&u.lhs, pol),
|
||||
Ty::Binary(b) => {
|
||||
let (lhs, rhs) = b.repr();
|
||||
let [lhs, rhs] = b.operands();
|
||||
self.analyze(lhs, pol);
|
||||
self.analyze(rhs, pol);
|
||||
}
|
||||
|
@ -203,7 +204,7 @@ impl<'a, 'b> TypeSimplifier<'a, 'b> {
|
|||
Ty::Args(args) => Ty::Args(self.transform_sig(args, !pol)),
|
||||
Ty::Unary(u) => Ty::Unary(TypeUnary::new(u.op, self.transform(&u.lhs, pol).into())),
|
||||
Ty::Binary(b) => {
|
||||
let (lhs, rhs) = b.repr();
|
||||
let [lhs, rhs] = b.operands();
|
||||
let lhs = self.transform(lhs, pol);
|
||||
let rhs = self.transform(rhs, pol);
|
||||
|
||||
|
@ -272,9 +273,9 @@ impl<'a, 'b> TypeSimplifier<'a, 'b> {
|
|||
|
||||
fn transform_sig(&mut self, sig: &SigTy, pol: bool) -> Interned<SigTy> {
|
||||
let mut sig = sig.clone();
|
||||
sig.types = self.transform_seq(&sig.types, !pol);
|
||||
if let Some(ret) = &sig.ret {
|
||||
sig.ret = Some(self.transform(ret, pol));
|
||||
sig.inputs = self.transform_seq(&sig.inputs, !pol);
|
||||
if let Some(ret) = &sig.body {
|
||||
sig.body = Some(self.transform(ret, pol));
|
||||
}
|
||||
|
||||
// todo: we can reduce one clone by early compare on sig.types
|
||||
|
|
|
@ -42,7 +42,7 @@ impl<'a> Sig<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
Some((arguments, sig.ret.clone()))
|
||||
Some((arguments, sig.body.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ mod tests {
|
|||
struct CallCollector(Vec<Ty>);
|
||||
|
||||
impl ApplyChecker for CallCollector {
|
||||
fn call(
|
||||
fn apply(
|
||||
&mut self,
|
||||
sig: super::Sig,
|
||||
arguments: &crate::adt::interner::Interned<super::ArgsTy>,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue