mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-08-04 18:28:02 +00:00
feat: introduce type context trait TyCtx
(#670)
* feat: introduce `TyCtx` * core: simplify import * feat: implement local bind apis * build: update cargo.lock * dev: rename `LocalTyCtx` back to `TyCtxMut`
This commit is contained in:
parent
5898c60de1
commit
e9ec60d2b5
21 changed files with 417 additions and 240 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -4013,6 +4013,14 @@ version = "0.11.32"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea141357280a85cdacb962dc64b07ae6fa4381df468f6aba1d3dd93483afdc38"
|
||||
|
||||
[[package]]
|
||||
name = "tinymist-derive"
|
||||
version = "0.11.32"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinymist-query"
|
||||
version = "0.11.32"
|
||||
|
@ -4051,6 +4059,7 @@ dependencies = [
|
|||
"siphasher 1.0.1",
|
||||
"strum 0.26.3",
|
||||
"tinymist-analysis",
|
||||
"tinymist-derive",
|
||||
"tinymist-world",
|
||||
"toml 0.8.19",
|
||||
"triomphe",
|
||||
|
|
|
@ -23,6 +23,8 @@ once_cell = "1"
|
|||
paste = "1.0"
|
||||
cfg-if = "1.0"
|
||||
strum = { version = "0.26.2", features = ["derive"] }
|
||||
quote = "1"
|
||||
syn = "2"
|
||||
triomphe = { version = "0.1.10", default-features = false, features = ["std"] }
|
||||
|
||||
# Asynchoronous and Multi-threading
|
||||
|
@ -139,6 +141,7 @@ insta = { version = "1.39", features = ["glob"] }
|
|||
typst-preview = { path = "./crates/typst-preview/" }
|
||||
tinymist-assets = { version = "0.11.32" }
|
||||
tinymist = { path = "./crates/tinymist/" }
|
||||
tinymist-derive = { path = "./crates/tinymist-derive/" }
|
||||
tinymist-analysis = { path = "./crates/tinymist-analysis/" }
|
||||
tinymist-query = { path = "./crates/tinymist-query/" }
|
||||
tinymist-world = { path = "./crates/tinymist-world/" }
|
||||
|
|
21
crates/tinymist-derive/Cargo.toml
Normal file
21
crates/tinymist-derive/Cargo.toml
Normal file
|
@ -0,0 +1,21 @@
|
|||
[package]
|
||||
name = "tinymist-derive"
|
||||
description = "Provides derive for tinymist."
|
||||
categories = ["compilers"]
|
||||
keywords = ["typst"]
|
||||
authors.workspace = true
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
edition.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
syn.workspace = true
|
||||
quote.workspace = true
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[features]
|
||||
typst-preview = []
|
48
crates/tinymist-derive/src/lib.rs
Normal file
48
crates/tinymist-derive/src/lib.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, DeriveInput};
|
||||
|
||||
#[proc_macro_derive(BindTyCtx, attributes(bind))]
|
||||
pub fn bind_ty_ctx(input: TokenStream) -> TokenStream {
|
||||
// Parse the input tokens into a syntax tree
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
|
||||
// Build the output, possibly using quasi-quotation
|
||||
let expanded = match input.data {
|
||||
syn::Data::Struct(..) => {
|
||||
let name = &input.ident;
|
||||
let bind_name = input
|
||||
.attrs
|
||||
.iter()
|
||||
.find_map(|attr| {
|
||||
if attr.path().is_ident("bind") {
|
||||
Some(attr.parse_args::<syn::Expr>().unwrap())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
let t = syn::Ident::new("tyctx", input.ident.span());
|
||||
syn::parse_quote!(#t)
|
||||
});
|
||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
|
||||
quote! {
|
||||
impl #impl_generics TyCtx for #name #ty_generics #where_clause {
|
||||
fn global_bounds(&self, var: &Interned<TypeVar>, pol: bool) -> Option<TypeBounds> {
|
||||
self.#bind_name.global_bounds(var, pol)
|
||||
}
|
||||
fn local_bind_of(&self, var: &Interned<TypeVar>) -> Option<Ty> {
|
||||
self.#bind_name.local_bind_of(var)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => panic!("only structs are supported"),
|
||||
};
|
||||
|
||||
// Hand the output tokens back to the compiler
|
||||
TokenStream::from(expanded)
|
||||
}
|
|
@ -55,6 +55,7 @@ base64.workspace = true
|
|||
typlite.workspace = true
|
||||
tinymist-world.workspace = true
|
||||
tinymist-analysis.workspace = true
|
||||
tinymist-derive.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
once_cell.workspace = true
|
||||
|
|
|
@ -5,14 +5,17 @@ use std::{collections::HashMap, sync::Arc};
|
|||
use once_cell::sync::Lazy;
|
||||
use reflexo::vector::ir::DefId;
|
||||
use typst::{
|
||||
foundations::Value,
|
||||
foundations::{Func, Value},
|
||||
syntax::{
|
||||
ast::{self, AstNode},
|
||||
LinkedNode, Source, Span, SyntaxKind,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::analysis::{Ty, *};
|
||||
use crate::{
|
||||
adt::interner::Interned,
|
||||
analysis::{Ty, *},
|
||||
};
|
||||
use crate::{analysis::TypeScheme, ty::TypeInterface, AnalysisContext};
|
||||
|
||||
use super::{
|
||||
|
@ -61,6 +64,8 @@ enum InterpretMode {
|
|||
Math,
|
||||
}
|
||||
|
||||
#[derive(BindTyCtx)]
|
||||
#[bind(info)]
|
||||
struct TypeChecker<'a, 'w> {
|
||||
ctx: &'a mut AnalysisContext<'w>,
|
||||
source: Source,
|
||||
|
@ -71,6 +76,26 @@ struct TypeChecker<'a, 'w> {
|
|||
mode: InterpretMode,
|
||||
}
|
||||
|
||||
impl<'a, 'w> TyCtxMut for TypeChecker<'a, 'w> {
|
||||
type Snap = <TypeScheme as TyCtxMut>::Snap;
|
||||
|
||||
fn start_scope(&mut self) -> Self::Snap {
|
||||
self.info.start_scope()
|
||||
}
|
||||
|
||||
fn end_scope(&mut self, snap: Self::Snap) {
|
||||
self.info.end_scope(snap)
|
||||
}
|
||||
|
||||
fn bind_local(&mut self, var: &Interned<TypeVar>, ty: Ty) {
|
||||
self.info.bind_local(var, ty);
|
||||
}
|
||||
|
||||
fn type_of_func(&mut self, func: &Func) -> Option<Interned<SigTy>> {
|
||||
self.ctx.type_of_func(func)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'w> TypeChecker<'a, 'w> {
|
||||
fn check(&mut self, root: LinkedNode) -> Ty {
|
||||
let should_record = matches!(root.kind(), SyntaxKind::FuncCall).then(|| root.span());
|
||||
|
|
|
@ -9,6 +9,8 @@ use crate::{analysis::ApplyChecker, ty::ArgsTy};
|
|||
use super::*;
|
||||
use crate::adt::interner::Interned;
|
||||
|
||||
#[derive(BindTyCtx)]
|
||||
#[bind(base)]
|
||||
pub struct ApplyTypeChecker<'a, 'b, 'w> {
|
||||
pub(super) base: &'a mut TypeChecker<'b, 'w>,
|
||||
pub call_site: Span,
|
||||
|
@ -17,18 +19,6 @@ pub struct ApplyTypeChecker<'a, 'b, 'w> {
|
|||
}
|
||||
|
||||
impl<'a, 'b, 'w> ApplyChecker for ApplyTypeChecker<'a, 'b, 'w> {
|
||||
fn bound_of_var(
|
||||
&mut self,
|
||||
var: &Interned<super::TypeVar>,
|
||||
_pol: bool,
|
||||
) -> Option<super::TypeBounds> {
|
||||
self.base
|
||||
.info
|
||||
.vars
|
||||
.get(&var.def)
|
||||
.map(|v| v.bounds.bounds().read().clone())
|
||||
}
|
||||
|
||||
fn apply(&mut self, sig: Sig, args: &Interned<ArgsTy>, pol: bool) {
|
||||
let _ = self.args;
|
||||
|
||||
|
@ -38,7 +28,7 @@ impl<'a, 'b, 'w> ApplyChecker for ApplyTypeChecker<'a, 'b, 'w> {
|
|||
};
|
||||
|
||||
if !is_partialize {
|
||||
if let Some(ty) = sig.call(args, pol, Some(self.base.ctx)) {
|
||||
if let Some(ty) = sig.call(args, pol, self.base) {
|
||||
self.resultant.push(ty);
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +145,7 @@ impl<'a, 'b, 'w> ApplyChecker for ApplyTypeChecker<'a, 'b, 'w> {
|
|||
|
||||
let callee = sig.ty();
|
||||
|
||||
let Some(SigShape { sig, withs }) = sig.shape(Some(self.base.ctx)) else {
|
||||
let Some(SigShape { sig, withs }) = sig.shape(self.base) else {
|
||||
return;
|
||||
};
|
||||
for (arg_recv, arg_ins) in sig.matches(args, withs) {
|
||||
|
@ -210,24 +200,14 @@ impl<T: FnMut(&mut TypeChecker, Sig, bool)> TupleCheckDriver for T {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(BindTyCtx)]
|
||||
#[bind(base)]
|
||||
pub struct TupleChecker<'a, 'b, 'w> {
|
||||
pub(super) base: &'a mut TypeChecker<'b, 'w>,
|
||||
driver: &'a mut dyn TupleCheckDriver,
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'w> ApplyChecker for TupleChecker<'a, 'b, 'w> {
|
||||
fn bound_of_var(
|
||||
&mut self,
|
||||
var: &Interned<super::TypeVar>,
|
||||
_pol: bool,
|
||||
) -> Option<super::TypeBounds> {
|
||||
self.base
|
||||
.info
|
||||
.vars
|
||||
.get(&var.def)
|
||||
.map(|v| v.bounds.bounds().read().clone())
|
||||
}
|
||||
|
||||
fn apply(&mut self, sig: Sig, _args: &Interned<ArgsTy>, pol: bool) {
|
||||
self.driver.check(self.base, sig, pol);
|
||||
}
|
||||
|
|
|
@ -3,9 +3,13 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use hashbrown::HashSet;
|
||||
use typst::syntax::{
|
||||
ast::{self, AstNode},
|
||||
LinkedNode, Span, SyntaxKind,
|
||||
use tinymist_derive::BindTyCtx;
|
||||
use typst::{
|
||||
foundations::Func,
|
||||
syntax::{
|
||||
ast::{self, AstNode},
|
||||
LinkedNode, Span, SyntaxKind,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -15,7 +19,7 @@ use crate::{
|
|||
AnalysisContext,
|
||||
};
|
||||
|
||||
use super::{FieldTy, SigShape, Ty, TypeScheme};
|
||||
use super::{FieldTy, SigShape, SigTy, Ty, TyCtx, TyCtxMut, TypeScheme, TypeVar};
|
||||
|
||||
/// With given type information, check the type of a literal expression again by
|
||||
/// touching the possible related nodes.
|
||||
|
@ -27,6 +31,7 @@ pub(crate) fn post_type_check(
|
|||
let mut worker = PostTypeCheckWorker {
|
||||
ctx: _ctx,
|
||||
checked: HashMap::new(),
|
||||
locals: TypeScheme::default(),
|
||||
info,
|
||||
};
|
||||
|
||||
|
@ -62,7 +67,7 @@ fn check_signature<'a>(
|
|||
target: &'a ParamTarget,
|
||||
) -> impl FnMut(&mut PostTypeCheckWorker, Sig, &[Interned<ArgsTy>], bool) -> Option<()> + 'a {
|
||||
move |worker, sig, args, pol| {
|
||||
let SigShape { sig: sig_ins, .. } = sig.shape(Some(worker.ctx))?;
|
||||
let SigShape { sig: sig_ins, .. } = sig.shape(worker)?;
|
||||
|
||||
match &target {
|
||||
ParamTarget::Named(n) => {
|
||||
|
@ -105,10 +110,43 @@ fn check_signature<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
// #[derive(BindTyCtx)]
|
||||
// #[bind(info)]
|
||||
struct PostTypeCheckWorker<'a, 'w> {
|
||||
ctx: &'a mut AnalysisContext<'w>,
|
||||
checked: HashMap<Span, Option<Ty>>,
|
||||
info: &'a TypeScheme,
|
||||
locals: TypeScheme,
|
||||
}
|
||||
|
||||
impl<'a, 'w> TyCtx for PostTypeCheckWorker<'a, 'w> {
|
||||
fn global_bounds(&self, var: &Interned<TypeVar>, pol: bool) -> Option<TypeBounds> {
|
||||
self.info.global_bounds(var, pol)
|
||||
}
|
||||
|
||||
fn local_bind_of(&self, var: &Interned<TypeVar>) -> Option<Ty> {
|
||||
self.locals.local_bind_of(var)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'w> TyCtxMut for PostTypeCheckWorker<'a, 'w> {
|
||||
type Snap = <TypeScheme as TyCtxMut>::Snap;
|
||||
|
||||
fn start_scope(&mut self) -> Self::Snap {
|
||||
self.locals.start_scope()
|
||||
}
|
||||
|
||||
fn end_scope(&mut self, snap: Self::Snap) {
|
||||
self.locals.end_scope(snap)
|
||||
}
|
||||
|
||||
fn bind_local(&mut self, var: &Interned<TypeVar>, ty: Ty) {
|
||||
self.locals.bind_local(var, ty);
|
||||
}
|
||||
|
||||
fn type_of_func(&mut self, func: &Func) -> Option<Interned<SigTy>> {
|
||||
self.ctx.type_of_func(func)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'w> PostTypeCheckWorker<'a, 'w> {
|
||||
|
@ -289,20 +327,17 @@ impl<'a, 'w> PostTypeCheckWorker<'a, 'w> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_signatures(
|
||||
&mut self,
|
||||
ty: &Ty,
|
||||
pol: bool,
|
||||
checker: &mut impl FnMut(&mut Self, Sig, &[Interned<ArgsTy>], bool) -> Option<()>,
|
||||
) {
|
||||
ty.sig_surface(pol, SigSurfaceKind::Call, &mut (self, checker));
|
||||
fn check_signatures(&mut self, ty: &Ty, pol: bool, checker: &mut impl PostSigChecker) {
|
||||
let mut checker = PostSigCheckWorker(self, checker);
|
||||
ty.sig_surface(pol, SigSurfaceKind::Call, &mut checker);
|
||||
}
|
||||
|
||||
fn check_element_of<T>(&mut self, ty: &Ty, pol: bool, context: &LinkedNode, checker: &mut T)
|
||||
where
|
||||
T: FnMut(&mut Self, Sig, &[Interned<ArgsTy>], bool) -> Option<()>,
|
||||
T: PostSigChecker,
|
||||
{
|
||||
ty.sig_surface(pol, sig_context_of(context), &mut (self, checker))
|
||||
let mut checker = PostSigCheckWorker(self, checker);
|
||||
ty.sig_surface(pol, sig_context_of(context), &mut checker)
|
||||
}
|
||||
|
||||
fn simplify(&mut self, ty: &Ty) -> Option<Ty> {
|
||||
|
@ -310,29 +345,43 @@ impl<'a, 'w> PostTypeCheckWorker<'a, 'w> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'w, T> SigChecker for (&mut PostTypeCheckWorker<'a, 'w>, &mut T)
|
||||
trait PostSigChecker {
|
||||
fn check(
|
||||
&mut self,
|
||||
checker: &mut PostTypeCheckWorker,
|
||||
sig: Sig,
|
||||
args: &[Interned<ArgsTy>],
|
||||
pol: bool,
|
||||
) -> Option<()>;
|
||||
}
|
||||
|
||||
impl<T> PostSigChecker for T
|
||||
where
|
||||
T: FnMut(&mut PostTypeCheckWorker<'a, 'w>, Sig, &[Interned<ArgsTy>], bool) -> Option<()>,
|
||||
T: FnMut(&mut PostTypeCheckWorker, Sig, &[Interned<ArgsTy>], bool) -> Option<()>,
|
||||
{
|
||||
fn check(
|
||||
&mut self,
|
||||
checker: &mut PostTypeCheckWorker,
|
||||
sig: Sig,
|
||||
args: &[Interned<ArgsTy>],
|
||||
pol: bool,
|
||||
) -> Option<()> {
|
||||
self(checker, sig, args, pol)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(BindTyCtx)]
|
||||
#[bind(0)]
|
||||
struct PostSigCheckWorker<'x, 'a, 'w, T>(&'x mut PostTypeCheckWorker<'a, 'w>, &'x mut T);
|
||||
|
||||
impl<'x, 'a, 'w, T: PostSigChecker> SigChecker for PostSigCheckWorker<'x, 'a, 'w, T> {
|
||||
fn check(
|
||||
&mut self,
|
||||
sig: Sig,
|
||||
args: &mut crate::analysis::SigCheckContext,
|
||||
pol: bool,
|
||||
) -> Option<()> {
|
||||
self.1(self.0, sig, &args.args, pol)
|
||||
}
|
||||
|
||||
fn check_var(
|
||||
&mut self,
|
||||
var: &Interned<crate::analysis::TypeVar>,
|
||||
_pol: bool,
|
||||
) -> Option<TypeBounds> {
|
||||
self.0
|
||||
.info
|
||||
.vars
|
||||
.get(&var.def)
|
||||
.map(|v| v.bounds.bounds().read().clone())
|
||||
self.1.check(self.0, sig, &args.args, pol)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ use crate::analysis::Ty;
|
|||
use super::*;
|
||||
use crate::adt::interner::Interned;
|
||||
|
||||
#[derive(BindTyCtx)]
|
||||
#[bind(base)]
|
||||
pub struct SelectFieldChecker<'a, 'b, 'w> {
|
||||
pub(super) base: &'a mut TypeChecker<'b, 'w>,
|
||||
pub select_site: Span,
|
||||
|
@ -16,18 +18,6 @@ pub struct SelectFieldChecker<'a, 'b, 'w> {
|
|||
}
|
||||
|
||||
impl<'a, 'b, 'w> SelectChecker for SelectFieldChecker<'a, 'b, 'w> {
|
||||
fn bound_of_var(
|
||||
&mut self,
|
||||
var: &Interned<super::TypeVar>,
|
||||
_pol: bool,
|
||||
) -> Option<super::TypeBounds> {
|
||||
self.base
|
||||
.info
|
||||
.vars
|
||||
.get(&var.def)
|
||||
.map(|v| v.bounds.bounds().read().clone())
|
||||
}
|
||||
|
||||
fn select(&mut self, iface: Iface, key: &Interned<str>, pol: bool) {
|
||||
log::debug!("selecting field: {iface:?} {key:?}");
|
||||
let _ = pol;
|
||||
|
|
|
@ -1,18 +1,13 @@
|
|||
use once_cell::sync::Lazy;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use crate::{adt::interner::Interned, ty::def::*};
|
||||
use super::{Sig, SigChecker, SigSurfaceKind, TyCtx};
|
||||
use crate::ty::def::*;
|
||||
|
||||
use super::{Sig, SigChecker, SigSurfaceKind};
|
||||
|
||||
pub trait ApplyChecker {
|
||||
pub trait ApplyChecker: TyCtx {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
static EMPTY_ARGS: Lazy<Interned<ArgsTy>> = Lazy::new(|| ArgsTy::default().into());
|
||||
static EMPTY_ARGS: LazyLock<Interned<ArgsTy>> = LazyLock::new(|| ArgsTy::default().into());
|
||||
|
||||
impl Ty {
|
||||
/// Call the given type with the given arguments.
|
||||
|
@ -42,7 +37,9 @@ impl Ty {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct ApplySigChecker<'a, T>(&'a mut T, &'a Interned<ArgsTy>);
|
||||
#[derive(BindTyCtx)]
|
||||
#[bind(0)]
|
||||
pub struct ApplySigChecker<'a, T: ApplyChecker>(&'a mut T, &'a Interned<ArgsTy>);
|
||||
|
||||
impl<'a, T: ApplyChecker> ApplySigChecker<'a, T> {
|
||||
fn ty(&mut self, ty: &Ty, surface: SigSurfaceKind, pol: bool) {
|
||||
|
@ -65,8 +62,4 @@ impl<'a, T: ApplyChecker> SigChecker for ApplySigChecker<'a, T> {
|
|||
self.0.apply(partial_sig, self.1, pol);
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn check_var(&mut self, _var: &Interned<TypeVar>, _pol: bool) -> Option<TypeBounds> {
|
||||
self.0.bound_of_var(_var, _pol)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
use crate::{adt::interner::Interned, ty::def::*};
|
||||
use crate::ty::def::*;
|
||||
|
||||
pub trait BoundChecker {
|
||||
pub trait BoundChecker: TyCtx {
|
||||
fn collect(&mut self, ty: &Ty, pol: bool);
|
||||
fn bound_of_var(&mut self, _var: &Interned<TypeVar>, _pol: bool) -> Option<TypeBounds> {
|
||||
}
|
||||
|
||||
impl<T> TyCtx for T
|
||||
where
|
||||
T: FnMut(&Ty, bool) -> Option<TypeBounds>,
|
||||
{
|
||||
fn local_bind_of(&self, _var: &Interned<TypeVar>) -> Option<Ty> {
|
||||
None
|
||||
}
|
||||
fn global_bounds(&self, _var: &Interned<TypeVar>, _pol: bool) -> Option<TypeBounds> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> BoundChecker for T
|
||||
where
|
||||
T: FnMut(&Ty, bool) -> Option<TypeBounds>,
|
||||
|
@ -53,7 +61,7 @@ impl BoundCheckContext {
|
|||
self.tys(u.lbs.iter(), !pol, checker);
|
||||
}
|
||||
Ty::Var(u) => {
|
||||
let Some(w) = checker.bound_of_var(u, pol) else {
|
||||
let Some(w) = checker.global_bounds(u, pol) else {
|
||||
return;
|
||||
};
|
||||
self.tys(w.ubs.iter(), pol, checker);
|
||||
|
|
|
@ -9,7 +9,7 @@ use typst::{
|
|||
layout::Length,
|
||||
};
|
||||
|
||||
use crate::{adt::interner::Interned, ty::*};
|
||||
use crate::ty::*;
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, EnumIter)]
|
||||
pub enum PathPreference {
|
||||
|
|
|
@ -19,14 +19,19 @@ use typst::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
adt::interner::{impl_internable, Interned},
|
||||
adt::{interner::impl_internable, snapshot_map},
|
||||
analysis::BuiltinTy,
|
||||
};
|
||||
|
||||
pub use tinymist_derive::BindTyCtx;
|
||||
|
||||
pub(crate) use super::{TyCtxMut, TyCtx};
|
||||
pub(crate) use crate::adt::interner::Interned;
|
||||
|
||||
/// A reference to the interned type
|
||||
pub(super) type TyRef = Interned<Ty>;
|
||||
pub(crate) type TyRef = Interned<Ty>;
|
||||
/// A reference to the interned string
|
||||
pub(super) type StrRef = Interned<str>;
|
||||
pub(crate) type StrRef = Interned<str>;
|
||||
|
||||
/// All possible types in tinymist
|
||||
#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
@ -949,12 +954,25 @@ impl IfTy {
|
|||
pub struct TypeScheme {
|
||||
/// The typing on definitions
|
||||
pub vars: HashMap<DefId, TypeVarBounds>,
|
||||
/// The local binding of the type variable
|
||||
pub local_binds: snapshot_map::SnapshotMap<DefId, Ty>,
|
||||
/// The typing on syntax structures
|
||||
pub mapping: HashMap<Span, Vec<Ty>>,
|
||||
|
||||
pub(super) cano_cache: Mutex<TypeCanoStore>,
|
||||
}
|
||||
|
||||
impl TyCtx for TypeScheme {
|
||||
fn global_bounds(&self, var: &Interned<TypeVar>, _pol: bool) -> Option<TypeBounds> {
|
||||
let v = self.vars.get(&var.def)?;
|
||||
Some(v.bounds.bounds().read().clone())
|
||||
}
|
||||
|
||||
fn local_bind_of(&self, var: &Interned<TypeVar>) -> Option<Ty> {
|
||||
self.local_binds.get(&var.def).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeScheme {
|
||||
/// Get the type of a definition
|
||||
pub fn type_of_def(&self, def: DefId) -> Option<Ty> {
|
||||
|
@ -997,6 +1015,26 @@ impl TypeScheme {
|
|||
}
|
||||
}
|
||||
|
||||
impl TyCtxMut for TypeScheme {
|
||||
type Snap = ena::undo_log::Snapshot;
|
||||
|
||||
fn start_scope(&mut self) -> Self::Snap {
|
||||
self.local_binds.snapshot()
|
||||
}
|
||||
|
||||
fn end_scope(&mut self, snap: Self::Snap) {
|
||||
self.local_binds.rollback_to(snap);
|
||||
}
|
||||
|
||||
fn bind_local(&mut self, var: &Interned<TypeVar>, ty: Ty) {
|
||||
self.local_binds.insert(var.def, ty);
|
||||
}
|
||||
|
||||
fn type_of_func(&mut self, _func: &typst::foundations::Func) -> Option<Interned<SigTy>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// A type variable bounds
|
||||
#[derive(Clone)]
|
||||
pub struct TypeVarBounds {
|
||||
|
@ -1049,7 +1087,7 @@ impl TypeVarBounds {
|
|||
/// A type variable bounds
|
||||
#[derive(Clone)]
|
||||
pub enum FlowVarKind {
|
||||
/// A type variable that receives both types and values (type instnaces)
|
||||
/// A type variable that receives both types and values (type instances)
|
||||
Strong(Arc<RwLock<TypeBounds>>),
|
||||
/// A type variable that receives only types
|
||||
/// The received values will be lifted to types
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::collections::HashSet;
|
|||
use reflexo::hash::hash128;
|
||||
use typst::foundations::Repr;
|
||||
|
||||
use crate::{adt::interner::Interned, analysis::*, ty::def::*};
|
||||
use crate::{analysis::*, ty::def::*};
|
||||
|
||||
impl TypeScheme {
|
||||
/// Describe the given type with the given type scheme.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use typst::foundations::{Dict, Value};
|
||||
|
||||
use crate::{adt::interner::Interned, analysis::*, ty::def::*};
|
||||
use crate::{analysis::*, ty::def::*};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Iface<'a> {
|
||||
|
@ -56,20 +56,8 @@ impl<'a> Iface<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait IfaceChecker {
|
||||
pub trait IfaceChecker: TyCtx {
|
||||
fn check(&mut self, sig: Iface, args: &mut IfaceCheckContext, pol: bool) -> Option<()>;
|
||||
fn check_var(&mut self, _var: &Interned<TypeVar>, _pol: bool) -> Option<TypeBounds> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IfaceChecker for T
|
||||
where
|
||||
T: FnMut(Iface, &mut IfaceCheckContext, bool) -> Option<()>,
|
||||
{
|
||||
fn check(&mut self, sig: Iface, args: &mut IfaceCheckContext, pol: bool) -> Option<()> {
|
||||
self(sig, args, pol)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ty {
|
||||
|
@ -98,6 +86,8 @@ pub struct IfaceCheckContext {
|
|||
pub at: TyRef,
|
||||
}
|
||||
|
||||
#[derive(BindTyCtx)]
|
||||
#[bind(checker)]
|
||||
pub struct IfaceCheckDriver<'a> {
|
||||
ctx: IfaceCheckContext,
|
||||
checker: &'a mut dyn IfaceChecker,
|
||||
|
@ -107,10 +97,6 @@ impl BoundChecker for IfaceCheckDriver<'_> {
|
|||
fn collect(&mut self, ty: &Ty, pol: bool) {
|
||||
self.ty(ty, pol);
|
||||
}
|
||||
|
||||
fn bound_of_var(&mut self, var: &Interned<TypeVar>, pol: bool) -> Option<TypeBounds> {
|
||||
self.checker.check_var(var, pol)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IfaceCheckDriver<'a> {
|
||||
|
|
|
@ -20,6 +20,61 @@ pub(crate) use iface::*;
|
|||
pub(crate) use mutate::*;
|
||||
pub(crate) use select::*;
|
||||
pub(crate) use sig::*;
|
||||
use typst::foundations::Func;
|
||||
|
||||
/// A type context.
|
||||
pub trait TyCtx {
|
||||
/// Get local binding of a variable.
|
||||
fn local_bind_of(&self, _var: &Interned<TypeVar>) -> Option<Ty>;
|
||||
/// Get the type of a variable.
|
||||
fn global_bounds(&self, _var: &Interned<TypeVar>, _pol: bool) -> Option<TypeBounds>;
|
||||
}
|
||||
|
||||
/// A mutable type context.
|
||||
pub trait TyCtxMut: TyCtx {
|
||||
/// The type of a snapshot of the scope.
|
||||
type Snap;
|
||||
|
||||
/// Start a new scope.
|
||||
#[must_use]
|
||||
fn start_scope(&mut self) -> Self::Snap;
|
||||
/// End the current scope.
|
||||
fn end_scope(&mut self, snap: Self::Snap);
|
||||
/// Execute a function with a new scope.
|
||||
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
|
||||
}
|
||||
|
||||
/// Bind a variable locally.
|
||||
fn bind_local(&mut self, var: &Interned<TypeVar>, ty: Ty);
|
||||
/// Get the type of a runtime function.
|
||||
fn type_of_func(&mut self, func: &Func) -> Option<Interned<SigTy>>;
|
||||
}
|
||||
|
||||
impl TyCtx for () {
|
||||
fn local_bind_of(&self, _var: &Interned<TypeVar>) -> Option<Ty> {
|
||||
None
|
||||
}
|
||||
fn global_bounds(&self, _var: &Interned<TypeVar>, _pol: bool) -> Option<TypeBounds> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl TyCtxMut for () {
|
||||
type Snap = ();
|
||||
|
||||
fn start_scope(&mut self) -> Self::Snap {
|
||||
Self::Snap::default()
|
||||
}
|
||||
fn end_scope(&mut self, _snap: Self::Snap) {}
|
||||
|
||||
fn bind_local(&mut self, _var: &Interned<TypeVar>, _ty: Ty) {}
|
||||
fn type_of_func(&mut self, _func: &Func) -> Option<Interned<SigTy>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
@ -1,7 +1,28 @@
|
|||
use crate::{adt::interner::Interned, ty::def::*};
|
||||
use crate::ty::def::*;
|
||||
|
||||
pub trait MutateDriver {
|
||||
fn mutate(&mut self, ty: &Ty, pol: bool) -> Option<Ty>;
|
||||
pub trait TyMutator {
|
||||
fn mutate(&mut self, ty: &Ty, pol: bool) -> Option<Ty> {
|
||||
self.mutate_rec(ty, pol)
|
||||
}
|
||||
fn mutate_rec(&mut self, ty: &Ty, pol: bool) -> Option<Ty> {
|
||||
use Ty::*;
|
||||
match ty {
|
||||
Value(..) | Any | Boolean(..) | Builtin(..) => None,
|
||||
Union(v) => Some(Union(self.mutate_vec(v, pol)?)),
|
||||
Var(..) | Let(..) => None,
|
||||
Array(e) => Some(Array(self.mutate(e, pol)?.into())),
|
||||
Dict(r) => Some(Dict(self.mutate_record(r, pol)?.into())),
|
||||
Tuple(e) => Some(Tuple(self.mutate_vec(e, pol)?)),
|
||||
Func(f) => Some(Func(self.mutate_func(f, pol)?.into())),
|
||||
Args(args) => Some(Args(self.mutate_func(args, pol)?.into())),
|
||||
Field(f) => Some(Field(self.mutate_field(f, pol)?.into())),
|
||||
Select(s) => Some(Select(self.mutate_select(s, pol)?.into())),
|
||||
With(w) => Some(With(self.mutate_with_sig(w, pol)?.into())),
|
||||
Unary(u) => Some(Unary(self.mutate_unary(u, pol)?.into())),
|
||||
Binary(b) => Some(Binary(self.mutate_binary(b, pol)?.into())),
|
||||
If(i) => Some(If(self.mutate_if(i, pol)?.into())),
|
||||
}
|
||||
}
|
||||
|
||||
fn mutate_vec(&mut self, ty: &[Ty], pol: bool) -> Option<Interned<Vec<Ty>>> {
|
||||
let mut mutated = false;
|
||||
|
@ -49,6 +70,13 @@ pub trait MutateDriver {
|
|||
})
|
||||
}
|
||||
|
||||
fn mutate_field(&mut self, f: &Interned<FieldTy>, pol: bool) -> Option<FieldTy> {
|
||||
let field = self.mutate(&f.field, pol)?;
|
||||
let mut f = f.as_ref().clone();
|
||||
f.field = field;
|
||||
Some(f)
|
||||
}
|
||||
|
||||
fn mutate_record(&mut self, ty: &Interned<RecordTy>, pol: bool) -> Option<RecordTy> {
|
||||
let types = self.mutate_vec(&ty.types, pol)?;
|
||||
|
||||
|
@ -121,7 +149,7 @@ pub trait MutateDriver {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> MutateDriver for T
|
||||
impl<T> TyMutator for T
|
||||
where
|
||||
T: FnMut(&Ty, bool) -> Option<Ty>,
|
||||
{
|
||||
|
@ -132,37 +160,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)
|
||||
}
|
||||
}
|
||||
|
||||
struct Mutator;
|
||||
|
||||
impl Mutator {
|
||||
fn ty(&mut self, ty: &Ty, pol: bool, mutator: &mut impl MutateDriver) -> Option<Ty> {
|
||||
use Ty::*;
|
||||
match ty {
|
||||
Value(..) | Any | Boolean(..) | Builtin(..) => mutator.mutate(ty, pol),
|
||||
Union(v) => Some(Union(mutator.mutate_vec(v, pol)?)),
|
||||
Var(..) | Let(..) => mutator.mutate(ty, pol),
|
||||
Array(e) => Some(Array(mutator.mutate(e, pol)?.into())),
|
||||
Dict(r) => Some(Dict(mutator.mutate_record(r, pol)?.into())),
|
||||
Tuple(e) => Some(Tuple(mutator.mutate_vec(e, pol)?)),
|
||||
Func(f) => Some(Func(mutator.mutate_func(f, pol)?.into())),
|
||||
Args(args) => Some(Args(mutator.mutate_func(args, pol)?.into())),
|
||||
Field(f) => {
|
||||
let field = f.field.mutate(pol, mutator)?;
|
||||
let mut f = f.as_ref().clone();
|
||||
f.field = field;
|
||||
Some(Field(f.into()))
|
||||
}
|
||||
Select(s) => Some(Select(mutator.mutate_select(s, pol)?.into())),
|
||||
With(w) => Some(With(mutator.mutate_with_sig(w, pol)?.into())),
|
||||
Unary(u) => Some(Unary(mutator.mutate_unary(u, pol)?.into())),
|
||||
Binary(b) => Some(Binary(mutator.mutate_binary(b, pol)?.into())),
|
||||
If(i) => Some(If(mutator.mutate_if(i, pol)?.into())),
|
||||
}
|
||||
pub fn mutate(&self, pol: bool, checker: &mut impl TyMutator) -> Option<Ty> {
|
||||
checker.mutate(self, pol)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
use crate::{adt::interner::Interned, ty::def::*};
|
||||
|
||||
use super::{Iface, IfaceChecker};
|
||||
use crate::ty::def::*;
|
||||
|
||||
pub trait SelectChecker {
|
||||
pub trait SelectChecker: TyCtx {
|
||||
fn select(&mut self, sig: Iface, key: &Interned<str>, pol: bool);
|
||||
|
||||
fn bound_of_var(&mut self, _var: &Interned<TypeVar>, _pol: bool) -> Option<TypeBounds> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Ty {
|
||||
|
@ -17,7 +12,9 @@ impl Ty {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct SelectKeyChecker<'a, T>(&'a mut T, &'a Interned<str>);
|
||||
#[derive(BindTyCtx)]
|
||||
#[bind(0)]
|
||||
pub struct SelectKeyChecker<'a, T: TyCtx>(&'a mut T, &'a Interned<str>);
|
||||
|
||||
impl<'a, T: SelectChecker> SelectKeyChecker<'a, T> {
|
||||
fn ty(&mut self, ty: &Ty, pol: bool) {
|
||||
|
@ -35,8 +32,4 @@ impl<'a, T: SelectChecker> IfaceChecker for SelectKeyChecker<'a, T> {
|
|||
self.0.select(iface, self.1, pol);
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn check_var(&mut self, _var: &Interned<TypeVar>, _pol: bool) -> Option<TypeBounds> {
|
||||
self.0.bound_of_var(_var, _pol)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use typst::foundations::{Func, Value};
|
||||
|
||||
use crate::{adt::interner::Interned, analysis::*, ty::def::*};
|
||||
use crate::{analysis::*, ty::def::*};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Sig<'a> {
|
||||
|
@ -45,7 +45,7 @@ impl<'a> Sig<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn shape(self, ctx: Option<&mut AnalysisContext>) -> Option<SigShape<'a>> {
|
||||
pub fn shape(self, ctx: &mut impl TyCtxMut) -> Option<SigShape<'a>> {
|
||||
let (cano_sig, withs) = match self {
|
||||
Sig::With { sig, withs, .. } => (*sig, Some(withs)),
|
||||
_ => (self, None),
|
||||
|
@ -56,8 +56,8 @@ impl<'a> Sig<'a> {
|
|||
Sig::ArrayCons(a) => SigTy::array_cons(a.as_ref().clone(), false),
|
||||
Sig::TupleCons(t) => SigTy::tuple_cons(t.clone(), false),
|
||||
Sig::DictCons(d) => SigTy::dict_cons(d, false),
|
||||
Sig::TypeCons { val, .. } => ctx?.type_of_func(&val.constructor().ok()?)?,
|
||||
Sig::Value { val, .. } => ctx?.type_of_func(val)?,
|
||||
Sig::TypeCons { val, .. } => ctx.type_of_func(&val.constructor().ok()?)?,
|
||||
Sig::Value { val, .. } => ctx.type_of_func(val)?,
|
||||
// todo
|
||||
Sig::Partialize(..) => return None,
|
||||
Sig::With { .. } => return None,
|
||||
|
@ -79,20 +79,8 @@ pub enum SigSurfaceKind {
|
|||
ArrayOrDict,
|
||||
}
|
||||
|
||||
pub trait SigChecker {
|
||||
pub trait SigChecker: TyCtx {
|
||||
fn check(&mut self, sig: Sig, args: &mut SigCheckContext, pol: bool) -> Option<()>;
|
||||
fn check_var(&mut self, _var: &Interned<TypeVar>, _pol: bool) -> Option<TypeBounds> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SigChecker for T
|
||||
where
|
||||
T: FnMut(Sig, &mut SigCheckContext, bool) -> Option<()>,
|
||||
{
|
||||
fn check(&mut self, sig: Sig, args: &mut SigCheckContext, pol: bool) -> Option<()> {
|
||||
self(sig, args, pol)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ty {
|
||||
|
@ -121,14 +109,24 @@ impl Ty {
|
|||
|
||||
let mut primary = None;
|
||||
|
||||
#[derive(BindTyCtx)]
|
||||
#[bind(0)]
|
||||
struct SigReprDriver<'a, C: TyCtx>(&'a C, &'a mut Option<Interned<SigTy>>);
|
||||
|
||||
impl<C: TyCtx> SigChecker for SigReprDriver<'_, C> {
|
||||
fn check(&mut self, sig: Sig, _ctx: &mut SigCheckContext, _pol: bool) -> Option<()> {
|
||||
// todo: bind type context
|
||||
let sig = sig.shape(&mut ())?;
|
||||
*self.1 = Some(sig.sig.clone());
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
self.sig_surface(
|
||||
pol,
|
||||
SigSurfaceKind::Call,
|
||||
&mut |sig: Sig, _ctx: &mut SigCheckContext, _pol: bool| {
|
||||
let sig = sig.shape(None)?;
|
||||
primary = Some(sig.sig.clone());
|
||||
Some(())
|
||||
},
|
||||
// todo: bind type context
|
||||
&mut SigReprDriver(&(), &mut primary),
|
||||
);
|
||||
|
||||
primary
|
||||
|
@ -141,6 +139,8 @@ pub struct SigCheckContext {
|
|||
pub at: TyRef,
|
||||
}
|
||||
|
||||
#[derive(BindTyCtx)]
|
||||
#[bind(checker)]
|
||||
pub struct SigCheckDriver<'a> {
|
||||
ctx: SigCheckContext,
|
||||
checker: &'a mut dyn SigChecker,
|
||||
|
@ -252,12 +252,10 @@ impl BoundChecker for SigCheckDriver<'_> {
|
|||
log::debug!("sig bounds: {ty:?}");
|
||||
self.ty(ty, pol);
|
||||
}
|
||||
|
||||
fn bound_of_var(&mut self, var: &Interned<TypeVar>, pol: bool) -> Option<TypeBounds> {
|
||||
self.checker.check_var(var, pol)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(BindTyCtx)]
|
||||
#[bind(0)]
|
||||
struct MethodDriver<'a, 'b>(&'a mut SigCheckDriver<'b>, &'a StrRef);
|
||||
|
||||
impl<'a, 'b> MethodDriver<'a, 'b> {
|
||||
|
@ -327,8 +325,4 @@ impl<'a, 'b> BoundChecker for MethodDriver<'a, 'b> {
|
|||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn bound_of_var(&mut self, var: &Interned<TypeVar>, pol: bool) -> Option<TypeBounds> {
|
||||
self.0.checker.check_var(var, pol)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::collections::HashSet;
|
|||
use ecow::EcoVec;
|
||||
use reflexo::hash::hash128;
|
||||
|
||||
use crate::{adt::interner::Interned, analysis::*, ty::def::*};
|
||||
use crate::{analysis::*, ty::def::*};
|
||||
|
||||
#[derive(Default)]
|
||||
struct CompactTy {
|
||||
|
|
|
@ -1,79 +1,57 @@
|
|||
use hashbrown::HashMap;
|
||||
|
||||
use crate::{adt::interner::Interned, analysis::*, ty::def::*};
|
||||
use crate::{analysis::*, ty::def::*};
|
||||
|
||||
impl<'a> Sig<'a> {
|
||||
pub fn call(
|
||||
&self,
|
||||
args: &Interned<ArgsTy>,
|
||||
pol: bool,
|
||||
ctx: Option<&mut AnalysisContext>,
|
||||
ctx: &mut impl TyCtxMut,
|
||||
) -> Option<Ty> {
|
||||
let (bound_variables, body) = self.check_bind(args, ctx)?;
|
||||
ctx.with_scope(|ctx| {
|
||||
let body = self.check_bind(args, ctx)?;
|
||||
|
||||
if bound_variables.is_empty() {
|
||||
return body;
|
||||
}
|
||||
|
||||
let body = body?;
|
||||
|
||||
// Substitute the bound variables in the body or just body
|
||||
let mut checker = SubstituteChecker { bound_variables };
|
||||
Some(checker.ty(&body, pol).unwrap_or(body))
|
||||
// Substitute the bound variables in the body or just body
|
||||
let mut checker = SubstituteChecker { ctx };
|
||||
Some(checker.ty(&body, pol).unwrap_or(body))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn check_bind(
|
||||
&self,
|
||||
args: &Interned<ArgsTy>,
|
||||
ctx: Option<&mut AnalysisContext>,
|
||||
) -> Option<(HashMap<DefId, Ty>, Option<Ty>)> {
|
||||
pub fn check_bind(&self, args: &Interned<ArgsTy>, ctx: &mut impl TyCtxMut) -> Option<Ty> {
|
||||
let SigShape { sig, withs } = self.shape(ctx)?;
|
||||
|
||||
// todo: check if the signature has free variables
|
||||
// let has_free_vars = sig.has_free_variables;
|
||||
let has_free_vars = true;
|
||||
|
||||
let mut arguments = HashMap::new();
|
||||
if has_free_vars {
|
||||
for (arg_recv, arg_ins) in sig.matches(args, withs) {
|
||||
if let Ty::Var(arg_recv) = arg_recv {
|
||||
arguments.insert(arg_recv.def, arg_ins.clone());
|
||||
}
|
||||
for (arg_recv, arg_ins) in sig.matches(args, withs) {
|
||||
if let Ty::Var(arg_recv) = arg_recv {
|
||||
ctx.bind_local(arg_recv, arg_ins.clone());
|
||||
}
|
||||
}
|
||||
|
||||
Some((arguments, sig.body.clone()))
|
||||
sig.body.clone()
|
||||
}
|
||||
}
|
||||
|
||||
struct SubstituteChecker {
|
||||
bound_variables: HashMap<DefId, Ty>,
|
||||
struct SubstituteChecker<'a, T: TyCtxMut> {
|
||||
ctx: &'a mut T,
|
||||
}
|
||||
|
||||
impl SubstituteChecker {
|
||||
impl<'a, T: TyCtxMut> SubstituteChecker<'a, T> {
|
||||
fn ty(&mut self, body: &Ty, pol: bool) -> Option<Ty> {
|
||||
body.mutate(pol, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl MutateDriver for SubstituteChecker {
|
||||
impl<'a, T: TyCtxMut> TyMutator for SubstituteChecker<'a, T> {
|
||||
fn mutate(&mut self, ty: &Ty, pol: bool) -> Option<Ty> {
|
||||
// todo: extrude the type into a polarized type
|
||||
let _ = pol;
|
||||
|
||||
Some(match ty {
|
||||
// todo: substitute the bound in the type
|
||||
Ty::Let(..) => return None,
|
||||
Ty::Var(v) => {
|
||||
if let Some(ty) = self.bound_variables.get(&v.def) {
|
||||
ty.clone()
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Ty::Value(..) | Ty::Any | Ty::Boolean(..) | Ty::Builtin(..) => return None,
|
||||
_ => return None,
|
||||
})
|
||||
if let Ty::Var(v) = ty {
|
||||
self.ctx.local_bind_of(v)
|
||||
} else {
|
||||
self.mutate_rec(ty, pol)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,7 +61,7 @@ mod tests {
|
|||
|
||||
use crate::ty::tests::*;
|
||||
|
||||
use super::{ApplyChecker, Ty};
|
||||
use super::{ApplyChecker, Interned, Ty, TyCtx, TypeBounds, TypeVar};
|
||||
#[test]
|
||||
fn test_ty() {
|
||||
use super::*;
|
||||
|
@ -95,6 +73,14 @@ mod tests {
|
|||
#[derive(Default)]
|
||||
struct CallCollector(Vec<Ty>);
|
||||
|
||||
impl TyCtx for CallCollector {
|
||||
fn local_bind_of(&self, _var: &Interned<TypeVar>) -> Option<Ty> {
|
||||
None
|
||||
}
|
||||
fn global_bounds(&self, _var: &Interned<TypeVar>, _pol: bool) -> Option<TypeBounds> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl ApplyChecker for CallCollector {
|
||||
fn apply(
|
||||
&mut self,
|
||||
|
@ -102,7 +88,7 @@ mod tests {
|
|||
arguments: &crate::adt::interner::Interned<super::ArgsTy>,
|
||||
pol: bool,
|
||||
) {
|
||||
let ty = sig.call(arguments, pol, None);
|
||||
let ty = sig.call(arguments, pol, &mut ());
|
||||
if let Some(ty) = ty {
|
||||
self.0.push(ty);
|
||||
}
|
||||
|
@ -128,7 +114,7 @@ mod tests {
|
|||
})
|
||||
}
|
||||
|
||||
assert_snapshot!(call(literal_sig!(p1 -> p1), literal_args!(q1)), @"@q1");
|
||||
assert_snapshot!(call(literal_sig!(!u1: w1 -> w1), literal_args!(!u1: w2)), @"@w2");
|
||||
assert_snapshot!(call(literal_sig!(p1 -> p1), literal_args!(q1)), @"@p1");
|
||||
assert_snapshot!(call(literal_sig!(!u1: w1 -> w1), literal_args!(!u1: w2)), @"@w1");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue