feat: infer types of show rule transformers (#1045)

* feat: infer types of show rule transformers

* test: add test for show rules

* feat: more selector cases

* test: update snapshot
This commit is contained in:
Myriad-Dreamin 2024-12-22 10:42:07 +08:00 committed by GitHub
parent 458695b3a0
commit 5db1cf984a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 119 additions and 4 deletions

View file

@ -1,5 +1,7 @@
//! Type checking on source file
use typst::foundations::{Element, Type};
use super::*;
use crate::analysis::ParamAttrs;
use crate::docs::{SignatureDocsT, TypelessParamDocs, UntypedDefDocs};
@ -434,13 +436,66 @@ impl TypeChecker<'_> {
}
fn check_show(&mut self, show: &Interned<ShowExpr>) -> Ty {
let _selector = show.selector.as_ref().map(|sel| self.check(sel));
// todo: infer it type by selector
let _transform = self.check(&show.edit);
let selector = show.selector.as_ref().map(|sel| self.check(sel));
let transform = self.check(&show.edit);
self.constraint_show(selector, transform);
Ty::Builtin(BuiltinTy::None)
}
fn constraint_show(&mut self, selector: Option<Ty>, transform: Ty) -> Option<()> {
crate::log_debug_ct!("show on {selector:?}, transform {transform:?}");
let selected = match selector {
Some(selector) => Self::content_by_selector(selector)?,
None => Ty::Builtin(BuiltinTy::Content),
};
let show_fact = Ty::Func(SigTy::unary(selected, Ty::Any));
crate::log_debug_ct!("check show_fact type {show_fact:?} value: {transform:?}");
self.constrain(&transform, &show_fact);
Some(())
}
fn content_by_selector(selector: Ty) -> Option<Ty> {
crate::log_debug_ct!("check selector {selector:?}");
Some(match selector {
Ty::With(with) => return Self::content_by_selector(with.sig.as_ref().clone()),
Ty::Builtin(BuiltinTy::Type(ty)) => {
if ty == Type::of::<typst::foundations::Regex>() {
Ty::Builtin(BuiltinTy::Element(Element::of::<typst::text::TextElem>()))
} else {
return None;
}
}
Ty::Builtin(BuiltinTy::Element(..)) => selector,
Ty::Value(ins_ty) => match &ins_ty.val {
Value::Str(..) => {
Ty::Builtin(BuiltinTy::Element(Element::of::<typst::text::TextElem>()))
}
Value::Content(c) => Ty::Builtin(BuiltinTy::Element(c.elem())),
Value::Func(f) => {
if let Some(elem) = f.element() {
Ty::Builtin(BuiltinTy::Element(elem))
} else {
return None;
}
}
Value::Dyn(value) => {
if value.ty() == Type::of::<typst::foundations::Regex>() {
Ty::Builtin(BuiltinTy::Element(Element::of::<typst::text::TextElem>()))
} else {
return None;
}
}
_ => return None,
},
_ => return None,
})
}
// todo: merge with func call, and regard difference (may be here)
fn check_set(&mut self, set: &Interned<SetExpr>) -> Ty {
let callee = self.check(&set.target);

View file

@ -15,7 +15,7 @@ snapshot_kind: text
"labelDetails": {
"description": "(str, align: alignment, block: bool, lang: none | str, syntaxes: [syntax], tab-size: int, theme: [theme]) => raw"
},
"sortText": "052",
"sortText": "053",
"textEdit": {
"newText": "raw(${1:})",
"range": {

View file

@ -0,0 +1,5 @@
/// contains: text
#show regex(":\S+:"): it => it./* range 0..1 */
:test:

View file

@ -0,0 +1,5 @@
/// contains: text
#show raw: it => it./* range 0..1 */
:test:

View file

@ -0,0 +1,5 @@
/// contains: text
#show raw.where(block: false): it => it./* range 0..1 */
:test:

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: result
input_file: crates/tinymist-query/src/fixtures/type_check/show.typ
snapshot_kind: text
---
"" = (Any) => Any.it
"it" = Element(text)
=====
26..31 -> Type(regex)
26..40 -> Type(regex)
42..44 -> @it
42..51 -> @
48..50 -> @it
48..51 -> @v"it".it

View file

@ -0,0 +1,14 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: result
input_file: crates/tinymist-query/src/fixtures/type_check/show_raw.typ
snapshot_kind: text
---
"" = (Any) => Any.it
"it" = Element(raw)
=====
26..29 -> Func(raw)
31..33 -> @it
31..40 -> @
37..39 -> @it
37..40 -> @v"it".it

View file

@ -0,0 +1,16 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: result
input_file: crates/tinymist-query/src/fixtures/type_check/show_raw_where.typ
snapshot_kind: text
---
"" = (Any) => Any.it
"it" = Element(raw)
=====
26..29 -> Func(raw)
26..35 -> (Func(raw) | Func(raw).where)
26..49 -> (Func(raw)).with(..("block": false) => any)
51..53 -> @it
51..60 -> @
57..59 -> @it
57..60 -> @v"it".it