mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-07-24 13:13:43 +00:00
feat: incorporated with static function signature analysis (#688)
* feat: finished function signature analysis * dev: update snapshot * dev: broken snapshot
This commit is contained in:
parent
a3f100e7cb
commit
02bbdbf8d9
26 changed files with 429 additions and 270 deletions
|
@ -19,7 +19,7 @@ use std::{
|
|||
fmt::{self, Debug, Display},
|
||||
hash::{BuildHasherDefault, Hash, Hasher},
|
||||
ops::Deref,
|
||||
sync::OnceLock,
|
||||
sync::{LazyLock, OnceLock},
|
||||
};
|
||||
|
||||
use dashmap::{DashMap, SharedValue};
|
||||
|
@ -95,6 +95,13 @@ impl Interned<str> {
|
|||
}
|
||||
}
|
||||
|
||||
static EMPTY: LazyLock<Interned<str>> = LazyLock::new(|| Interned::new_str(""));
|
||||
impl Default for Interned<str> {
|
||||
fn default() -> Self {
|
||||
EMPTY.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Interned<str> {
|
||||
fn from(s: &str) -> Self {
|
||||
Interned::new_str(s)
|
||||
|
@ -249,6 +256,32 @@ impl PartialEq for Interned<str> {
|
|||
|
||||
impl Eq for Interned<str> {}
|
||||
|
||||
impl serde::Serialize for Interned<str> {
|
||||
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
self.arc.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for Interned<str> {
|
||||
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
struct StrVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for StrVisitor {
|
||||
type Value = Interned<str>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a string")
|
||||
}
|
||||
|
||||
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
|
||||
Ok(Interned::new_str(v))
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_str(StrVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Internable + ?Sized> Hash for Interned<T> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
// NOTE: Cast disposes vtable pointer / slice/str length.
|
||||
|
|
|
@ -73,7 +73,7 @@ pub fn analyze_call_no_cache(
|
|||
callee_node: LinkedNode,
|
||||
args: ast::Args<'_>,
|
||||
) -> Option<CallInfo> {
|
||||
let signature = analyze_signature(ctx, SignatureTarget::Syntax(source, callee_node))?;
|
||||
let signature = analyze_signature(ctx, SignatureTarget::SyntaxFast(source, callee_node))?;
|
||||
trace!("got signature {signature:?}");
|
||||
|
||||
let mut info = CallInfo {
|
||||
|
|
|
@ -16,10 +16,9 @@ use typst::syntax::{package::PackageSpec, Span, VirtualPath};
|
|||
use typst::{model::Document, text::Font};
|
||||
use typst_shim::syntax::LinkedNodeExt;
|
||||
|
||||
use crate::adt::interner::Interned;
|
||||
use crate::analysis::{
|
||||
analyze_bib, analyze_dyn_signature, analyze_expr_, analyze_import_, post_type_check, BibInfo,
|
||||
DefUseInfo, DefinitionLink, DocString, IdentRef, ImportInfo, PathPreference, SigTy, Signature,
|
||||
analyze_bib, analyze_expr_, analyze_import_, analyze_signature, post_type_check, BibInfo,
|
||||
DefUseInfo, DefinitionLink, DocString, IdentRef, ImportInfo, PathPreference, Signature,
|
||||
SignatureTarget, Ty, TypeScheme,
|
||||
};
|
||||
use crate::docs::{DocStringKind, SignatureDocs};
|
||||
|
@ -460,8 +459,14 @@ impl<'w> AnalysisContext<'w> {
|
|||
|
||||
Some(self.to_lsp_range(position, &source))
|
||||
}
|
||||
|
||||
pub(crate) fn signature_dyn(&mut self, func: Func) -> Signature {
|
||||
log::debug!("check runtime func {func:?}");
|
||||
analyze_signature(self, SignatureTarget::Runtime(func)).unwrap()
|
||||
}
|
||||
|
||||
/// Get the signature of a function.
|
||||
pub fn signature(&self, func: &SignatureTarget) -> Option<Signature> {
|
||||
pub fn get_signature(&self, func: &SignatureTarget) -> Option<Signature> {
|
||||
match func {
|
||||
SignatureTarget::Def(source, r) => {
|
||||
// todo: check performance on peeking signature source frequently
|
||||
|
@ -472,6 +477,15 @@ impl<'w> AnalysisContext<'w> {
|
|||
.get(&hash128(&cache_key))
|
||||
.and_then(|slot| (cache_key.1 == slot.2).then_some(slot.3.clone()))
|
||||
}
|
||||
SignatureTarget::SyntaxFast(source, node) => {
|
||||
// todo: check performance on peeking signature source frequently
|
||||
let cache_key = (source, node.offset(), true);
|
||||
self.analysis
|
||||
.caches
|
||||
.static_signatures
|
||||
.get(&hash128(&cache_key))
|
||||
.and_then(|slot| (cache_key.1 == slot.2).then_some(slot.3.clone()))
|
||||
}
|
||||
SignatureTarget::Syntax(source, node) => {
|
||||
// todo: check performance on peeking signature source frequently
|
||||
let cache_key = (source, node.offset());
|
||||
|
@ -507,6 +521,16 @@ impl<'w> AnalysisContext<'w> {
|
|||
});
|
||||
slot.3.clone()
|
||||
}
|
||||
SignatureTarget::SyntaxFast(source, node) => {
|
||||
let cache_key = (source, node.offset(), true);
|
||||
self.analysis
|
||||
.caches
|
||||
.static_signatures
|
||||
.entry(hash128(&cache_key))
|
||||
.or_insert_with(|| (self.lifetime, cache_key.0, cache_key.1, compute()))
|
||||
.3
|
||||
.clone()
|
||||
}
|
||||
SignatureTarget::Syntax(source, node) => {
|
||||
let cache_key = (source, node.offset());
|
||||
self.analysis
|
||||
|
@ -537,7 +561,7 @@ impl<'w> AnalysisContext<'w> {
|
|||
runtime_fn: &Value,
|
||||
) -> Option<SignatureDocs> {
|
||||
let def_use = self.def_use(source.clone())?;
|
||||
let ty_chk = self.type_check(source.clone())?;
|
||||
let ty_chk = self.type_check(source)?;
|
||||
crate::docs::signature_docs(self, Some(&(def_use, ty_chk)), def_ident, runtime_fn, None)
|
||||
}
|
||||
|
||||
|
@ -560,7 +584,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<TypeScheme>> {
|
||||
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() {
|
||||
|
@ -574,7 +598,7 @@ impl<'w> AnalysisContext<'w> {
|
|||
let res = if let Some(res) = self.analysis.caches.type_check.get(&h) {
|
||||
res.1.clone()
|
||||
} else {
|
||||
let res = crate::analysis::type_check(self, source);
|
||||
let res = crate::analysis::type_check(self, source.clone());
|
||||
self.analysis
|
||||
.caches
|
||||
.type_check
|
||||
|
@ -691,18 +715,13 @@ impl<'w> AnalysisContext<'w> {
|
|||
self.type_of_span(rr.span())
|
||||
}
|
||||
|
||||
pub(crate) fn type_of_func(&mut self, func: &Func) -> Option<Interned<SigTy>> {
|
||||
log::debug!("check runtime func {func:?}");
|
||||
Some(analyze_dyn_signature(self, func.clone()).type_sig())
|
||||
}
|
||||
|
||||
pub(crate) fn user_type_of_ident(
|
||||
&mut self,
|
||||
source: &Source,
|
||||
def_fid: TypstFileId,
|
||||
def_ident: &IdentRef,
|
||||
) -> Option<Ty> {
|
||||
let ty_chk = self.type_check(source.clone())?;
|
||||
let ty_chk = self.type_check(source)?;
|
||||
let def_use = self.def_use(source.clone())?;
|
||||
|
||||
let (def_id, _) = def_use.get_def(def_fid, def_ident)?;
|
||||
|
@ -721,14 +740,17 @@ impl<'w> AnalysisContext<'w> {
|
|||
pub(crate) fn type_of_span(&mut self, s: Span) -> Option<Ty> {
|
||||
let id = s.id()?;
|
||||
let source = self.source_by_id(id).ok()?;
|
||||
let ty_chk = self.type_check(source)?;
|
||||
ty_chk.type_of_span(s)
|
||||
self.type_of_span_(&source, s)
|
||||
}
|
||||
|
||||
pub(crate) fn type_of_span_(&mut self, source: &Source, s: Span) -> Option<Ty> {
|
||||
self.type_check(source)?.type_of_span(s)
|
||||
}
|
||||
|
||||
pub(crate) fn literal_type_of_node(&mut self, k: LinkedNode) -> Option<Ty> {
|
||||
let id = k.span().id()?;
|
||||
let source = self.source_by_id(id).ok()?;
|
||||
let ty_chk = self.type_check(source.clone())?;
|
||||
let ty_chk = self.type_check(&source)?;
|
||||
|
||||
post_type_check(self, &ty_chk, k.clone()).or_else(|| ty_chk.type_of_span(k.span()))
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ impl<'a, 'w> TyCtxMut for PostTypeCheckWorker<'a, 'w> {
|
|||
}
|
||||
|
||||
fn type_of_func(&mut self, func: &Func) -> Option<Interned<SigTy>> {
|
||||
self.ctx.type_of_func(func)
|
||||
Some(self.ctx.signature_dyn(func.clone()).type_sig())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ use std::collections::BTreeMap;
|
|||
use std::sync::Arc;
|
||||
|
||||
use ecow::{eco_format, eco_vec, EcoString, EcoVec};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use typst::foundations::ParamInfo;
|
||||
use typst::syntax::Source;
|
||||
use typst::{
|
||||
foundations::{Closure, Func, Value},
|
||||
|
@ -12,17 +14,71 @@ use typst::{
|
|||
LinkedNode, SyntaxKind,
|
||||
},
|
||||
};
|
||||
use typst_shim::syntax::LinkedNodeExt;
|
||||
use typst_shim::utils::LazyHash;
|
||||
|
||||
use super::{IdentRef, StrRef};
|
||||
use crate::adt::interner::Interned;
|
||||
use crate::analysis::resolve_callee;
|
||||
use crate::syntax::{get_def_target, get_deref_target, DefTarget};
|
||||
use crate::ty::SigTy;
|
||||
use crate::analysis::{resolve_callee, AnalysisContext};
|
||||
use crate::docs::UntypedSymbolDocs;
|
||||
use crate::syntax::get_non_strict_def_target;
|
||||
use crate::ty::{SigTy, Ty};
|
||||
use crate::upstream::truncated_repr;
|
||||
use crate::AnalysisContext;
|
||||
|
||||
use super::{find_definition, DefinitionLink, IdentRef, LexicalKind, LexicalVarKind, StrRef, Ty};
|
||||
/// Describes a function parameter.
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
|
||||
pub struct ParamAttrs {
|
||||
/// Is the parameter positional?
|
||||
pub positional: bool,
|
||||
/// Is the parameter named?
|
||||
///
|
||||
/// Can be true even if `positional` is true if the parameter can be given
|
||||
/// in both variants.
|
||||
pub named: bool,
|
||||
/// Can the parameter be given any number of times?
|
||||
pub variadic: bool,
|
||||
/// Is the parameter settable with a set rule?
|
||||
pub settable: bool,
|
||||
}
|
||||
|
||||
impl ParamAttrs {
|
||||
pub(crate) fn positional() -> ParamAttrs {
|
||||
ParamAttrs {
|
||||
positional: true,
|
||||
named: false,
|
||||
variadic: false,
|
||||
settable: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn named() -> ParamAttrs {
|
||||
ParamAttrs {
|
||||
positional: false,
|
||||
named: true,
|
||||
variadic: false,
|
||||
settable: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn variadic() -> ParamAttrs {
|
||||
ParamAttrs {
|
||||
positional: true,
|
||||
named: false,
|
||||
variadic: true,
|
||||
settable: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&ParamInfo> for ParamAttrs {
|
||||
fn from(param: &ParamInfo) -> Self {
|
||||
ParamAttrs {
|
||||
positional: param.positional,
|
||||
named: param.named,
|
||||
variadic: param.variadic,
|
||||
settable: param.settable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes a function parameter.
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -35,17 +91,8 @@ pub struct ParamSpec {
|
|||
pub default: Option<EcoString>,
|
||||
/// The type of the parameter.
|
||||
pub ty: Ty,
|
||||
/// Is the parameter positional?
|
||||
pub positional: bool,
|
||||
/// Is the parameter named?
|
||||
///
|
||||
/// Can be true even if `positional` is true if the parameter can be given
|
||||
/// in both variants.
|
||||
pub named: bool,
|
||||
/// Can the parameter be given any number of times?
|
||||
pub variadic: bool,
|
||||
/// Is the parameter settable with a set rule?
|
||||
pub settable: bool,
|
||||
/// The attributes of the parameter.
|
||||
pub attrs: ParamAttrs,
|
||||
}
|
||||
|
||||
/// Describes a function signature.
|
||||
|
@ -90,7 +137,7 @@ pub struct PrimarySignature {
|
|||
pub param_specs: Vec<ParamSpec>,
|
||||
/// Whether the function has fill, stroke, or size parameters.
|
||||
pub has_fill_or_size_or_stroke: bool,
|
||||
/// The signature type.
|
||||
/// The associated signature type.
|
||||
pub(crate) sig_ty: Interned<SigTy>,
|
||||
_broken: bool,
|
||||
}
|
||||
|
@ -168,48 +215,126 @@ pub enum SignatureTarget<'a> {
|
|||
/// A static node without knowing the function at runtime.
|
||||
Def(Source, IdentRef),
|
||||
/// A static node without knowing the function at runtime.
|
||||
SyntaxFast(Source, LinkedNode<'a>),
|
||||
/// A static node without knowing the function at runtime.
|
||||
Syntax(Source, LinkedNode<'a>),
|
||||
/// A function that is known at runtime.
|
||||
Runtime(Func),
|
||||
}
|
||||
|
||||
pub(crate) fn analyze_dyn_signature(ctx: &mut AnalysisContext, func: Func) -> Signature {
|
||||
ctx.compute_signature(SignatureTarget::Runtime(func.clone()), || {
|
||||
Signature::Primary(analyze_dyn_signature_inner(func))
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn analyze_signature(
|
||||
ctx: &mut AnalysisContext,
|
||||
callee_node: SignatureTarget,
|
||||
) -> Option<Signature> {
|
||||
if let Some(sig) = ctx.signature(&callee_node) {
|
||||
if let Some(sig) = ctx.get_signature(&callee_node) {
|
||||
return Some(sig);
|
||||
}
|
||||
|
||||
analyze_type_signature(ctx, &callee_node).or_else(|| analyze_dyn_signature(ctx, &callee_node))
|
||||
}
|
||||
|
||||
fn analyze_type_signature(
|
||||
ctx: &mut AnalysisContext,
|
||||
callee_node: &SignatureTarget<'_>,
|
||||
) -> Option<Signature> {
|
||||
let (type_info, ty) = match callee_node {
|
||||
SignatureTarget::Def(..) => None,
|
||||
SignatureTarget::SyntaxFast(source, node) | SignatureTarget::Syntax(source, node) => {
|
||||
let type_info = ctx.type_check(source)?;
|
||||
let ty = type_info.type_of_span(node.span())?;
|
||||
Some((type_info, ty))
|
||||
}
|
||||
SignatureTarget::Runtime(f) => {
|
||||
let source = ctx.source_by_id(f.span().id()?).ok()?;
|
||||
let node = source.find(f.span())?;
|
||||
let def = get_non_strict_def_target(node.parent()?.clone())?;
|
||||
let type_info = ctx.type_check(&source)?;
|
||||
let ty = type_info.type_of_span(def.node().span())?;
|
||||
Some((type_info, ty))
|
||||
}
|
||||
}?;
|
||||
let type_var = ty.sources().into_iter().next()?;
|
||||
let sig_ty = ty.sig_repr(true)?;
|
||||
|
||||
let docstring = match type_info.var_docs.get(&type_var.def).map(|x| x.as_ref()) {
|
||||
Some(UntypedSymbolDocs::Function(sig)) => sig,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let mut param_specs = Vec::new();
|
||||
let mut has_fill_or_size_or_stroke = false;
|
||||
let mut _broken = false;
|
||||
|
||||
for (doc, ty) in docstring.pos.iter().zip(sig_ty.positional_params()) {
|
||||
let default = doc.default.clone();
|
||||
let ty = ty.clone();
|
||||
|
||||
let name = doc.name.clone();
|
||||
if matches!(name.as_ref(), "fill" | "stroke" | "size") {
|
||||
has_fill_or_size_or_stroke = true;
|
||||
}
|
||||
|
||||
param_specs.push(ParamSpec {
|
||||
name,
|
||||
docs: Some(doc.docs.clone()),
|
||||
default,
|
||||
ty,
|
||||
attrs: ParamAttrs::positional(),
|
||||
});
|
||||
}
|
||||
|
||||
for (name, ty) in sig_ty.named_params() {
|
||||
let doc = docstring.named.get(name).unwrap();
|
||||
let default = doc.default.clone();
|
||||
let ty = ty.clone();
|
||||
|
||||
if matches!(name.as_ref(), "fill" | "stroke" | "size") {
|
||||
has_fill_or_size_or_stroke = true;
|
||||
}
|
||||
|
||||
param_specs.push(ParamSpec {
|
||||
name: name.clone(),
|
||||
docs: Some(doc.docs.clone()),
|
||||
default,
|
||||
ty,
|
||||
attrs: ParamAttrs::named(),
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(doc) = docstring.rest.as_ref() {
|
||||
let default = doc.default.clone();
|
||||
|
||||
param_specs.push(ParamSpec {
|
||||
name: doc.name.clone(),
|
||||
docs: Some(doc.docs.clone()),
|
||||
default,
|
||||
ty: sig_ty.rest_param().cloned().unwrap_or(Ty::Any),
|
||||
attrs: ParamAttrs::variadic(),
|
||||
});
|
||||
}
|
||||
|
||||
Some(Signature::Primary(Arc::new(PrimarySignature {
|
||||
docs: Some(docstring.docs.clone()),
|
||||
param_specs,
|
||||
has_fill_or_size_or_stroke,
|
||||
sig_ty,
|
||||
_broken,
|
||||
})))
|
||||
}
|
||||
|
||||
fn analyze_dyn_signature(
|
||||
ctx: &mut AnalysisContext,
|
||||
callee_node: &SignatureTarget<'_>,
|
||||
) -> Option<Signature> {
|
||||
let func = match callee_node {
|
||||
SignatureTarget::Def(..) => todo!(),
|
||||
SignatureTarget::Syntax(source, node) => {
|
||||
let _ = resolve_callee_v2;
|
||||
let _ = source;
|
||||
|
||||
// let res = resolve_callee_v2(ctx, node)?;
|
||||
|
||||
// let func = match res {
|
||||
// TryResolveCalleeResult::Syntax(lnk) => {
|
||||
// println!("Syntax {:?}", lnk.name);
|
||||
|
||||
// return analyze_static_signature(ctx, source, lnk);
|
||||
// }
|
||||
// TryResolveCalleeResult::Runtime(func) => func,
|
||||
// };
|
||||
|
||||
let func = resolve_callee(ctx, &node)?;
|
||||
|
||||
SignatureTarget::Def(..) => return None,
|
||||
SignatureTarget::SyntaxFast(..) => return None,
|
||||
SignatureTarget::Syntax(_, node) => {
|
||||
let func = resolve_callee(ctx, node)?;
|
||||
log::debug!("got function {func:?}");
|
||||
func
|
||||
}
|
||||
SignatureTarget::Runtime(func) => func,
|
||||
SignatureTarget::Runtime(func) => func.clone(),
|
||||
};
|
||||
|
||||
use typst::foundations::func::Repr;
|
||||
|
@ -241,81 +366,12 @@ pub(crate) fn analyze_signature(
|
|||
if with_stack.is_empty() {
|
||||
return Some(Signature::Primary(signature));
|
||||
}
|
||||
|
||||
Some(Signature::Partial(Arc::new(PartialSignature {
|
||||
signature,
|
||||
with_stack,
|
||||
})))
|
||||
}
|
||||
|
||||
// fn analyze_static_signature(
|
||||
// ctx: &mut AnalysisContext<'_>,
|
||||
// source: Source,
|
||||
// lnk: DefinitionLink,
|
||||
// ) -> Option<Signature> {
|
||||
// let def_at = lnk.def_at?;
|
||||
// let def_source = if def_at.0 == source.id() {
|
||||
// source.clone()
|
||||
// } else {
|
||||
// ctx.source_by_id(def_at.0).ok()?
|
||||
// };
|
||||
|
||||
// let root = LinkedNode::new(def_source.root());
|
||||
// let def_node = root.leaf_at_compat(def_at.1.start + 1)?;
|
||||
// let def_node = get_def_target(def_node)?;
|
||||
// let def_node = match def_node {
|
||||
// DefTarget::Let(node) => node,
|
||||
// DefTarget::Import(_) => return None,
|
||||
// };
|
||||
|
||||
// println!("def_node {def_node:?}");
|
||||
|
||||
// None
|
||||
// }
|
||||
|
||||
#[allow(dead_code)]
|
||||
enum TryResolveCalleeResult {
|
||||
Syntax(DefinitionLink),
|
||||
Runtime(Func),
|
||||
}
|
||||
|
||||
/// Resolve a callee expression to a function but prefer to keep static.
|
||||
fn resolve_callee_v2(
|
||||
ctx: &mut AnalysisContext,
|
||||
callee: LinkedNode,
|
||||
) -> Option<TryResolveCalleeResult> {
|
||||
let source = ctx.source_by_id(callee.span().id()?).ok()?;
|
||||
let node = source.find(callee.span())?;
|
||||
let cursor = node.offset();
|
||||
let deref_target = get_deref_target(node, cursor)?;
|
||||
let def = find_definition(ctx, source.clone(), None, deref_target)?;
|
||||
if let LexicalKind::Var(LexicalVarKind::Function) = def.kind {
|
||||
if let Some(Value::Func(f)) = def.value {
|
||||
return Some(TryResolveCalleeResult::Runtime(f));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(def_at) = &def.def_at {
|
||||
let def_source = if def_at.0 == source.id() {
|
||||
source.clone()
|
||||
} else {
|
||||
ctx.source_by_id(def_at.0).ok()?
|
||||
};
|
||||
|
||||
let _t = ctx.type_check(source)?;
|
||||
|
||||
let root = LinkedNode::new(def_source.root());
|
||||
let def_node = root.leaf_at_compat(def_at.1.start + 1)?;
|
||||
let def_node = get_def_target(def_node)?;
|
||||
let _def_node = match def_node {
|
||||
DefTarget::Let(node) => node,
|
||||
DefTarget::Import(_) => return None,
|
||||
};
|
||||
}
|
||||
|
||||
Some(TryResolveCalleeResult::Syntax(def))
|
||||
}
|
||||
|
||||
fn analyze_dyn_signature_inner(func: Func) -> Arc<PrimarySignature> {
|
||||
let mut pos_tys = vec![];
|
||||
let mut named_tys = Vec::new();
|
||||
|
@ -326,37 +382,26 @@ fn analyze_dyn_signature_inner(func: Func) -> Arc<PrimarySignature> {
|
|||
let mut rest_spec = None;
|
||||
|
||||
let mut broken = false;
|
||||
let mut has_fill = false;
|
||||
let mut has_stroke = false;
|
||||
let mut has_size = false;
|
||||
let mut has_fill_or_size_or_stroke = false;
|
||||
|
||||
let mut add_param = |param: ParamSpec| {
|
||||
let name = param.name.clone();
|
||||
if param.named {
|
||||
match param.name.as_ref() {
|
||||
"fill" => {
|
||||
has_fill = true;
|
||||
}
|
||||
"stroke" => {
|
||||
has_stroke = true;
|
||||
}
|
||||
"size" => {
|
||||
has_size = true;
|
||||
}
|
||||
_ => {}
|
||||
if param.attrs.named {
|
||||
if matches!(name.as_ref(), "fill" | "stroke" | "size") {
|
||||
has_fill_or_size_or_stroke = true;
|
||||
}
|
||||
named_tys.push((name.clone(), param.ty.clone()));
|
||||
named_specs.insert(name.clone(), param.clone());
|
||||
}
|
||||
|
||||
if param.variadic {
|
||||
if param.attrs.variadic {
|
||||
if rest_ty.is_some() {
|
||||
broken = true;
|
||||
} else {
|
||||
rest_ty = Some(param.ty.clone());
|
||||
rest_spec = Some(param);
|
||||
}
|
||||
} else if param.positional {
|
||||
} else if param.attrs.positional {
|
||||
// todo: we have some params that are both positional and named
|
||||
pos_tys.push(param.ty.clone());
|
||||
param_specs.push(param);
|
||||
|
@ -377,10 +422,7 @@ fn analyze_dyn_signature_inner(func: Func) -> Arc<PrimarySignature> {
|
|||
docs: Some(p.docs.into()),
|
||||
default: p.default.map(|d| truncated_repr(&d())),
|
||||
ty: Ty::from_param_site(&func, p),
|
||||
positional: p.positional,
|
||||
named: p.named,
|
||||
variadic: p.variadic,
|
||||
settable: p.settable,
|
||||
attrs: p.into(),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -400,7 +442,7 @@ fn analyze_dyn_signature_inner(func: Func) -> Arc<PrimarySignature> {
|
|||
Arc::new(PrimarySignature {
|
||||
docs: func.docs().map(From::from),
|
||||
param_specs,
|
||||
has_fill_or_size_or_stroke: has_fill || has_stroke || has_size,
|
||||
has_fill_or_size_or_stroke,
|
||||
sig_ty: sig_ty.into(),
|
||||
_broken: broken,
|
||||
})
|
||||
|
@ -424,10 +466,7 @@ fn analyze_closure_signature(c: Arc<LazyHash<Closure>>, add_param: &mut impl FnM
|
|||
docs: None,
|
||||
default: None,
|
||||
ty: Ty::Any,
|
||||
positional: true,
|
||||
named: false,
|
||||
variadic: false,
|
||||
settable: false,
|
||||
attrs: ParamAttrs::positional(),
|
||||
});
|
||||
}
|
||||
// todo: pattern
|
||||
|
@ -438,10 +477,7 @@ fn analyze_closure_signature(c: Arc<LazyHash<Closure>>, add_param: &mut impl FnM
|
|||
docs: Some(eco_format!("Default value: {expr}")),
|
||||
default: Some(expr),
|
||||
ty: Ty::Any,
|
||||
positional: false,
|
||||
named: true,
|
||||
variadic: false,
|
||||
settable: true,
|
||||
attrs: ParamAttrs::named(),
|
||||
});
|
||||
}
|
||||
ast::Param::Spread(n) => {
|
||||
|
@ -451,10 +487,7 @@ fn analyze_closure_signature(c: Arc<LazyHash<Closure>>, add_param: &mut impl FnM
|
|||
docs: None,
|
||||
default: None,
|
||||
ty: Ty::Any,
|
||||
positional: true,
|
||||
named: false,
|
||||
variadic: true,
|
||||
settable: false,
|
||||
attrs: ParamAttrs::variadic(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ impl<'a, 'w> TyCtxMut for TypeChecker<'a, 'w> {
|
|||
}
|
||||
|
||||
fn type_of_func(&mut self, func: &Func) -> Option<Interned<SigTy>> {
|
||||
self.ctx.type_of_func(func)
|
||||
Some(self.ctx.signature_dyn(func.clone()).type_sig())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ impl<'a, 'w> TypeChecker<'a, 'w> {
|
|||
|
||||
let source = self.ctx.source_by_id(def_id).ok()?;
|
||||
let ext_def_use_info = self.ctx.def_use(source.clone())?;
|
||||
let ext_type_info = self.ctx.type_check(source)?;
|
||||
let ext_type_info = self.ctx.type_check(&source)?;
|
||||
let (ext_def_id, _) = ext_def_use_info.get_def(
|
||||
def_id,
|
||||
&IdentRef {
|
||||
|
|
|
@ -14,15 +14,6 @@ use super::*;
|
|||
const DOC_VARS: u64 = 0;
|
||||
|
||||
impl<'a, 'w> TypeChecker<'a, 'w> {
|
||||
pub fn check_func_docs(&mut self, root: &LinkedNode) -> Option<Arc<DocString>> {
|
||||
let closure = root.cast::<ast::Closure>()?;
|
||||
let documenting_id = closure
|
||||
.name()
|
||||
.and_then(|n| self.get_def_id(n.span(), &to_ident_ref(root, n)?))?;
|
||||
|
||||
self.check_docstring(root, DocStringKind::Function, documenting_id)
|
||||
}
|
||||
|
||||
pub fn check_var_docs(&mut self, root: &LinkedNode) -> Option<Arc<DocString>> {
|
||||
let lb = root.cast::<ast::LetBinding>()?;
|
||||
let first = lb.kind().bindings();
|
||||
|
@ -45,9 +36,7 @@ impl<'a, 'w> TypeChecker<'a, 'w> {
|
|||
let docs = find_docs_of(&self.source, def)?;
|
||||
|
||||
let docstring = self.ctx.compute_docstring(root.span().id()?, docs, kind)?;
|
||||
let res = Arc::new(docstring.take().rename_based_on(base_id, self));
|
||||
self.info.var_docs.insert(base_id, res.clone());
|
||||
Some(res)
|
||||
Some(Arc::new(docstring.take().rename_based_on(base_id, self)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,9 +12,14 @@ use typst::{
|
|||
};
|
||||
|
||||
use super::*;
|
||||
use crate::{adt::interner::Interned, ty::*};
|
||||
use crate::{
|
||||
adt::interner::Interned,
|
||||
docs::{DocStringKind, SignatureDocsT, TypelessParamDocs, UntypedSymbolDocs},
|
||||
ty::*,
|
||||
};
|
||||
|
||||
static EMPTY_DOCSTRING: LazyLock<DocString> = LazyLock::new(DocString::default);
|
||||
static EMPTY_VAR_DOC: LazyLock<VarDoc> = LazyLock::new(VarDoc::default);
|
||||
|
||||
impl<'a, 'w> TypeChecker<'a, 'w> {
|
||||
pub(crate) fn check_syntax(&mut self, root: LinkedNode) -> Option<Ty> {
|
||||
|
@ -374,12 +379,20 @@ impl<'a, 'w> TypeChecker<'a, 'w> {
|
|||
}
|
||||
|
||||
fn check_closure(&mut self, root: LinkedNode<'_>) -> Option<Ty> {
|
||||
let docstring = self.check_func_docs(&root);
|
||||
let docstring = docstring.as_deref().unwrap_or(&EMPTY_DOCSTRING);
|
||||
let closure: ast::Closure = root.cast()?;
|
||||
let def_id = closure
|
||||
.name()
|
||||
.and_then(|n| self.get_def_id(n.span(), &to_ident_ref(&root, n)?))?;
|
||||
|
||||
let docstring = self.check_docstring(&root, DocStringKind::Function, def_id);
|
||||
let docstring = docstring.as_deref().unwrap_or(&EMPTY_DOCSTRING);
|
||||
|
||||
log::debug!("check closure: {:?} -> {docstring:#?}", closure.name());
|
||||
|
||||
let mut pos_docs = vec![];
|
||||
let mut named_docs = BTreeMap::new();
|
||||
let mut rest_docs = None;
|
||||
|
||||
let mut pos = vec![];
|
||||
let mut named = BTreeMap::new();
|
||||
let mut defaults = BTreeMap::new();
|
||||
|
@ -389,6 +402,18 @@ impl<'a, 'w> TypeChecker<'a, 'w> {
|
|||
match param {
|
||||
ast::Param::Pos(pattern) => {
|
||||
pos.push(self.check_pattern(pattern, Ty::Any, docstring, root.clone()));
|
||||
if let ast::Pattern::Normal(ast::Expr::Ident(ident)) = pattern {
|
||||
let name = ident.get().into();
|
||||
|
||||
let param_doc = docstring.get_var(&name).unwrap_or(&EMPTY_VAR_DOC);
|
||||
pos_docs.push(TypelessParamDocs {
|
||||
name,
|
||||
docs: param_doc.docs.clone().unwrap_or_default(),
|
||||
cano_type: (),
|
||||
default: param_doc.default.clone(),
|
||||
attrs: ParamAttrs::positional(),
|
||||
});
|
||||
}
|
||||
}
|
||||
ast::Param::Named(e) => {
|
||||
let name = e.name().get().into();
|
||||
|
@ -401,7 +426,19 @@ impl<'a, 'w> TypeChecker<'a, 'w> {
|
|||
// optimize it, so I put a todo here.
|
||||
self.constrain(&exp, &v);
|
||||
named.insert(name.clone(), v);
|
||||
defaults.insert(name, exp);
|
||||
defaults.insert(name.clone(), exp);
|
||||
|
||||
let param_doc = docstring.get_var(&name).unwrap_or(&EMPTY_VAR_DOC);
|
||||
named_docs.insert(
|
||||
name.clone(),
|
||||
TypelessParamDocs {
|
||||
name: name.clone(),
|
||||
docs: param_doc.docs.clone().unwrap_or_default(),
|
||||
cano_type: (),
|
||||
default: param_doc.default.clone(),
|
||||
attrs: ParamAttrs::named(),
|
||||
},
|
||||
);
|
||||
}
|
||||
// todo: spread left/right
|
||||
ast::Param::Spread(a) => {
|
||||
|
@ -413,14 +450,35 @@ impl<'a, 'w> TypeChecker<'a, 'w> {
|
|||
}
|
||||
self.constrain(&exp, &v);
|
||||
rest = Some(v);
|
||||
|
||||
let param_doc = docstring
|
||||
.get_var(&e.get().as_str().into())
|
||||
.unwrap_or(&EMPTY_VAR_DOC);
|
||||
rest_docs = Some(TypelessParamDocs {
|
||||
name: e.get().as_str().into(),
|
||||
docs: param_doc.docs.clone().unwrap_or_default(),
|
||||
cano_type: (),
|
||||
default: param_doc.default.clone(),
|
||||
attrs: ParamAttrs::variadic(),
|
||||
});
|
||||
}
|
||||
// todo: ..(args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.info.var_docs.insert(
|
||||
def_id,
|
||||
Arc::new(UntypedSymbolDocs::Function(Box::new(SignatureDocsT {
|
||||
docs: docstring.docs.clone().unwrap_or_default(),
|
||||
pos: pos_docs,
|
||||
named: named_docs,
|
||||
rest: rest_docs,
|
||||
ret_ty: (),
|
||||
}))),
|
||||
);
|
||||
|
||||
let body = self.check_expr_in(closure.body().span(), root);
|
||||
// let res_ty = docstring.res_ty.clone().unwrap_or(body);
|
||||
let res_ty = if let Some(annotated) = &docstring.res_ty {
|
||||
self.constrain(&body, annotated);
|
||||
Ty::Let(Interned::new(TypeBounds {
|
||||
|
|
|
@ -113,7 +113,7 @@ impl StatefulRequest for CompletionRequest {
|
|||
Some(DerefTarget::Normal(SyntaxKind::Str, cano_expr)) => {
|
||||
let parent = cano_expr.parent()?;
|
||||
if matches!(parent.kind(), SyntaxKind::Named | SyntaxKind::Args) {
|
||||
let ty_chk = ctx.type_check(source.clone());
|
||||
let ty_chk = ctx.type_check(&source);
|
||||
if let Some(ty_chk) = ty_chk {
|
||||
let ty = ty_chk.type_of_span(cano_expr.span());
|
||||
log::debug!("check string ty: {ty:?}");
|
||||
|
|
|
@ -116,7 +116,7 @@ pub fn package_docs(
|
|||
let file_id = fid?;
|
||||
let src = world.source(file_id).ok()?;
|
||||
let def_use = ctx.def_use(src.clone())?;
|
||||
let ty_chck = ctx.type_check(src)?;
|
||||
let ty_chck = ctx.type_check(&src)?;
|
||||
Some((def_use, ty_chck))
|
||||
});
|
||||
let type_info = type_info.as_ref();
|
||||
|
|
|
@ -14,9 +14,10 @@ use typst::{
|
|||
};
|
||||
|
||||
use super::tidy::*;
|
||||
use crate::analysis::{analyze_dyn_signature, ParamSpec};
|
||||
use crate::analysis::{ParamAttrs, ParamSpec};
|
||||
use crate::docs::library;
|
||||
use crate::syntax::IdentRef;
|
||||
use crate::ty::Interned;
|
||||
use crate::{ty::Ty, AnalysisContext};
|
||||
|
||||
type TypeRepr = Option<(/* short */ String, /* long */ String)>;
|
||||
|
@ -54,13 +55,18 @@ impl fmt::Display for DocStringKind {
|
|||
}
|
||||
}
|
||||
|
||||
/// Documentation about a symbol (without type information).
|
||||
pub type UntypedSymbolDocs = SymbolDocsT<()>;
|
||||
/// Documentation about a symbol.
|
||||
pub type SymbolDocs = SymbolDocsT<TypeRepr>;
|
||||
|
||||
/// Documentation about a symbol.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "kind")]
|
||||
pub enum SymbolDocs {
|
||||
pub enum SymbolDocsT<T> {
|
||||
/// Documentation about a function.
|
||||
#[serde(rename = "func")]
|
||||
Function(Box<SignatureDocs>),
|
||||
Function(Box<SignatureDocsT<T>>),
|
||||
/// Documentation about a variable.
|
||||
#[serde(rename = "var")]
|
||||
Variable(TidyVarDocs),
|
||||
|
@ -75,14 +81,14 @@ pub enum SymbolDocs {
|
|||
},
|
||||
}
|
||||
|
||||
impl SymbolDocs {
|
||||
impl<T> SymbolDocsT<T> {
|
||||
/// Get the markdown representation of the documentation.
|
||||
pub fn docs(&self) -> &str {
|
||||
pub fn docs(&self) -> &EcoString {
|
||||
match self {
|
||||
Self::Function(docs) => docs.docs.as_str(),
|
||||
Self::Variable(docs) => docs.docs.as_str(),
|
||||
Self::Module(docs) => docs.docs.as_str(),
|
||||
Self::Plain { docs } => docs.as_str(),
|
||||
Self::Function(docs) => &docs.docs,
|
||||
Self::Variable(docs) => &docs.docs,
|
||||
Self::Module(docs) => &docs.docs,
|
||||
Self::Plain { docs } => docs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,21 +129,22 @@ pub(crate) fn symbol_docs(
|
|||
|
||||
/// Describes a primary function signature.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SignatureDocs {
|
||||
pub struct SignatureDocsT<T> {
|
||||
/// Documentation for the function.
|
||||
pub docs: EcoString,
|
||||
// pub return_ty: Option<EcoString>,
|
||||
// pub params: Vec<TidyParamDocs>,
|
||||
/// The positional parameters.
|
||||
pub pos: Vec<ParamDocs>,
|
||||
pub pos: Vec<ParamDocsT<T>>,
|
||||
/// The named parameters.
|
||||
pub named: BTreeMap<String, ParamDocs>,
|
||||
pub named: BTreeMap<Interned<str>, ParamDocsT<T>>,
|
||||
/// The rest parameter.
|
||||
pub rest: Option<ParamDocs>,
|
||||
pub rest: Option<ParamDocsT<T>>,
|
||||
/// The return type.
|
||||
pub ret_ty: TypeRepr,
|
||||
pub ret_ty: T,
|
||||
}
|
||||
|
||||
/// Documentation about a signature.
|
||||
pub type SignatureDocs = SignatureDocsT<TypeRepr>;
|
||||
|
||||
impl fmt::Display for SignatureDocs {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut is_first = true;
|
||||
|
@ -197,41 +204,35 @@ impl fmt::Display for SignatureDocs {
|
|||
}
|
||||
}
|
||||
|
||||
/// Documentation about a parameter (without type information).
|
||||
pub type TypelessParamDocs = ParamDocsT<()>;
|
||||
/// Documentation about a parameter.
|
||||
pub type ParamDocs = ParamDocsT<TypeRepr>;
|
||||
|
||||
/// Describes a function parameter.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ParamDocs {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct ParamDocsT<T> {
|
||||
/// The parameter's name.
|
||||
pub name: String,
|
||||
pub name: Interned<str>,
|
||||
/// Documentation for the parameter.
|
||||
pub docs: EcoString,
|
||||
/// Inferred type of the parameter.
|
||||
pub cano_type: TypeRepr,
|
||||
pub cano_type: T,
|
||||
/// The parameter's default name as value.
|
||||
pub default: Option<EcoString>,
|
||||
/// Is the parameter positional?
|
||||
pub positional: bool,
|
||||
/// Is the parameter named?
|
||||
///
|
||||
/// Can be true even if `positional` is true if the parameter can be given
|
||||
/// in both variants.
|
||||
pub named: bool,
|
||||
/// Can the parameter be given any number of times?
|
||||
pub variadic: bool,
|
||||
/// Is the parameter settable with a set rule?
|
||||
pub settable: bool,
|
||||
/// The attribute of the parameter.
|
||||
#[serde(flatten)]
|
||||
pub attrs: ParamAttrs,
|
||||
}
|
||||
|
||||
impl ParamDocs {
|
||||
fn new(param: &ParamSpec, ty: Option<&Ty>, doc_ty: Option<&mut ShowTypeRepr>) -> Self {
|
||||
Self {
|
||||
name: param.name.as_ref().to_owned(),
|
||||
name: param.name.as_ref().into(),
|
||||
docs: param.docs.clone().unwrap_or_default(),
|
||||
cano_type: format_ty(ty.or(Some(¶m.ty)), doc_ty),
|
||||
default: param.default.clone(),
|
||||
positional: param.positional,
|
||||
named: param.named,
|
||||
variadic: param.variadic,
|
||||
settable: param.settable,
|
||||
attrs: param.attrs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -276,7 +277,7 @@ pub(crate) fn signature_docs(
|
|||
}
|
||||
}
|
||||
|
||||
let sig = analyze_dyn_signature(ctx, func.clone());
|
||||
let sig = ctx.signature_dyn(func.clone());
|
||||
let def_id = type_info.and_then(|(def_use, _)| {
|
||||
let def_fid = func.span().id()?;
|
||||
let (def_id, _) = def_use.get_def(def_fid, def_ident?)?;
|
||||
|
@ -313,7 +314,7 @@ pub(crate) fn signature_docs(
|
|||
let named = named_in
|
||||
.map(|(param, ty)| {
|
||||
(
|
||||
param.name.as_ref().to_owned(),
|
||||
param.name.clone(),
|
||||
ParamDocs::new(param, ty, doc_ty.as_mut()),
|
||||
)
|
||||
})
|
||||
|
@ -323,7 +324,7 @@ pub(crate) fn signature_docs(
|
|||
let ret_ty = format_ty(ret_in, doc_ty.as_mut());
|
||||
|
||||
Some(SignatureDocs {
|
||||
docs: docstring.and_then(|x| x.docs.clone()).unwrap_or_default(),
|
||||
docs: docstring.map(|x| x.docs().clone()).unwrap_or_default(),
|
||||
pos,
|
||||
named,
|
||||
rest,
|
||||
|
|
|
@ -3,4 +3,4 @@ source: crates/tinymist-query/src/analysis.rs
|
|||
expression: CallSnapshot(result.as_deref())
|
||||
input_file: crates/tinymist-query/src/fixtures/call_info/builtin.typ
|
||||
---
|
||||
1 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "angle" }
|
||||
<nil>
|
||||
|
|
|
@ -3,6 +3,4 @@ source: crates/tinymist-query/src/analysis.rs
|
|||
expression: CallSnapshot(result.as_deref())
|
||||
input_file: crates/tinymist-query/src/fixtures/call_info/builtin_poly.typ
|
||||
---
|
||||
255 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "red" }
|
||||
255 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "green" }
|
||||
255 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "blue" }
|
||||
<nil>
|
||||
|
|
|
@ -3,4 +3,4 @@ source: crates/tinymist-query/src/analysis.rs
|
|||
expression: CallSnapshot(result.as_deref())
|
||||
input_file: crates/tinymist-query/src/fixtures/call_info/builtin_poly2.typ
|
||||
---
|
||||
"#fff" -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "red" }
|
||||
<nil>
|
||||
|
|
|
@ -3,5 +3,4 @@ source: crates/tinymist-query/src/analysis.rs
|
|||
expression: CallSnapshot(result.as_deref())
|
||||
input_file: crates/tinymist-query/src/fixtures/call_info/user_named.typ
|
||||
---
|
||||
y: 1 -> CallParamInfo { kind: Named, is_content_block: false, param_name: "y" }
|
||||
1 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "x" }
|
||||
<nil>
|
||||
|
|
|
@ -3,4 +3,4 @@ source: crates/tinymist-query/src/analysis.rs
|
|||
expression: CallSnapshot(result.as_deref())
|
||||
input_file: crates/tinymist-query/src/fixtures/call_info/user_named_with.typ
|
||||
---
|
||||
1 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "x" }
|
||||
<nil>
|
||||
|
|
|
@ -3,4 +3,4 @@ source: crates/tinymist-query/src/analysis.rs
|
|||
expression: CallSnapshot(result.as_deref())
|
||||
input_file: crates/tinymist-query/src/fixtures/call_info/user_named_with2.typ
|
||||
---
|
||||
y: 1 -> CallParamInfo { kind: Named, is_content_block: false, param_name: "y" }
|
||||
<nil>
|
||||
|
|
|
@ -3,4 +3,4 @@ source: crates/tinymist-query/src/analysis.rs
|
|||
expression: CallSnapshot(result.as_deref())
|
||||
input_file: crates/tinymist-query/src/fixtures/call_info/user_with.typ
|
||||
---
|
||||
1 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "y" }
|
||||
<nil>
|
||||
|
|
|
@ -3,4 +3,4 @@ source: crates/tinymist-query/src/analysis.rs
|
|||
expression: CallSnapshot(result.as_deref())
|
||||
input_file: crates/tinymist-query/src/fixtures/call_info/user_with2.typ
|
||||
---
|
||||
|
||||
<nil>
|
||||
|
|
|
@ -3,15 +3,8 @@ source: crates/tinymist-query/src/analysis.rs
|
|||
expression: result
|
||||
input_file: crates/tinymist-query/src/fixtures/type_check/annotation_var.typ
|
||||
---
|
||||
"f" = Any
|
||||
"mapper" = (Type(function) | (Any, Any) => Any)
|
||||
"x" = Any
|
||||
"x" = Any
|
||||
"y" = Any
|
||||
---
|
||||
56..62 -> @mapper
|
||||
66..67 -> @x
|
||||
69..70 -> @f
|
||||
75..76 -> @x
|
||||
75..83 -> Any
|
||||
81..82 -> @f
|
||||
|
|
|
@ -4,17 +4,12 @@ expression: result
|
|||
input_file: crates/tinymist-query/src/fixtures/type_check/tuple_map.typ
|
||||
---
|
||||
"a" = (1, )
|
||||
"b" = (Type(string), )
|
||||
"f" = (( ⪯ (Type(bytes) | Type(float) | Type(integer) | Type(label) | Type(string) | Type(type) | Type(version)))) => Type(string)
|
||||
"x" = Any
|
||||
"b" = (Any, )
|
||||
"f" = Undef
|
||||
---
|
||||
5..6 -> @a
|
||||
20..21 -> @f
|
||||
24..25 -> @x
|
||||
29..32 -> Type(string)
|
||||
29..35 -> Type(string)
|
||||
33..34 -> @x
|
||||
42..43 -> @b
|
||||
46..47 -> @a
|
||||
46..54 -> (Type(string), )
|
||||
46..54 -> (Any, )
|
||||
52..53 -> @f
|
||||
|
|
|
@ -3,7 +3,7 @@ use typst_shim::syntax::LinkedNodeExt;
|
|||
|
||||
use crate::{
|
||||
adt::interner::Interned,
|
||||
analysis::{analyze_dyn_signature, find_definition},
|
||||
analysis::find_definition,
|
||||
prelude::*,
|
||||
syntax::{get_check_target, get_deref_target, CheckTarget, ParamTarget},
|
||||
DocTooltip, LspParamInfo, SemanticRequest,
|
||||
|
@ -62,7 +62,7 @@ impl SemanticRequest for SignatureHelpRequest {
|
|||
function = &inner.0;
|
||||
}
|
||||
|
||||
let sig = analyze_dyn_signature(ctx, function.clone());
|
||||
let sig = ctx.signature_dyn(function.clone());
|
||||
let pos = sig.primary().pos();
|
||||
let named = sig.primary().named();
|
||||
let rest = sig.primary().rest();
|
||||
|
@ -91,7 +91,7 @@ impl SemanticRequest for SignatureHelpRequest {
|
|||
let mut real_offset = 0;
|
||||
let focus_name = OnceCell::new();
|
||||
for (i, (param, ty)) in pos.chain(named).chain(rest).enumerate() {
|
||||
if is_set && !param.settable {
|
||||
if is_set && !param.attrs.settable {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,43 @@ impl Ty {
|
|||
matches!(self, Ty::Union(_) | Ty::Let(_) | Ty::Var(_))
|
||||
}
|
||||
|
||||
/// Get the sources of the given type.
|
||||
pub fn sources(&self) -> Vec<Interned<TypeVar>> {
|
||||
let mut results = vec![];
|
||||
fn collect(ty: &Ty, results: &mut Vec<Interned<TypeVar>>) {
|
||||
use Ty::*;
|
||||
match ty {
|
||||
Any | Boolean(_) | If(..) | Builtin(..) | Value(..) => {}
|
||||
Dict(..) | Array(..) | Tuple(..) | Func(..) | Args(..) => {}
|
||||
Unary(..) | Binary(..) => {}
|
||||
Field(ty) => {
|
||||
collect(&ty.field, results);
|
||||
}
|
||||
Union(ty) => {
|
||||
for ty in ty.iter() {
|
||||
collect(ty, results);
|
||||
}
|
||||
}
|
||||
Let(ty) => {
|
||||
for ty in ty.ubs.iter() {
|
||||
collect(ty, results);
|
||||
}
|
||||
for ty in ty.lbs.iter() {
|
||||
collect(ty, results);
|
||||
}
|
||||
}
|
||||
Var(ty) => {
|
||||
results.push(ty.clone());
|
||||
}
|
||||
With(ty) => collect(&ty.sig, results),
|
||||
Select(ty) => collect(&ty.ty, results),
|
||||
}
|
||||
}
|
||||
|
||||
collect(self, &mut results);
|
||||
results
|
||||
}
|
||||
|
||||
/// Profile the bounds of the given type.
|
||||
pub fn bounds(&self, pol: bool, checker: &mut impl BoundChecker) {
|
||||
BoundCheckContext.ty(self, pol, checker);
|
||||
|
|
|
@ -21,7 +21,8 @@ use typst::{
|
|||
use super::PackageId;
|
||||
use crate::{
|
||||
adt::{interner::impl_internable, snapshot_map},
|
||||
analysis::{BuiltinTy, DocString},
|
||||
analysis::BuiltinTy,
|
||||
docs::UntypedSymbolDocs,
|
||||
};
|
||||
|
||||
pub(crate) use super::{TyCtx, TyCtxMut};
|
||||
|
@ -960,7 +961,7 @@ pub struct TypeScheme {
|
|||
/// The typing on definitions
|
||||
pub vars: HashMap<DefId, TypeVarBounds>,
|
||||
/// The checked documentation of definitions
|
||||
pub var_docs: HashMap<DefId, Arc<DocString>>,
|
||||
pub var_docs: HashMap<DefId, Arc<UntypedSymbolDocs>>,
|
||||
/// The local binding of the type variable
|
||||
pub local_binds: snapshot_map::SnapshotMap<DefId, Ty>,
|
||||
/// The typing on syntax structures
|
||||
|
|
|
@ -12,7 +12,7 @@ use typst::visualize::Color;
|
|||
|
||||
use super::{Completion, CompletionContext, CompletionKind};
|
||||
use crate::adt::interner::Interned;
|
||||
use crate::analysis::{analyze_dyn_signature, resolve_call_target, BuiltinTy, PathPreference, Ty};
|
||||
use crate::analysis::{resolve_call_target, BuiltinTy, PathPreference, Ty};
|
||||
use crate::syntax::{param_index_at_leaf, CheckTarget};
|
||||
use crate::upstream::complete::complete_code;
|
||||
use crate::upstream::plain_docs_sentence;
|
||||
|
@ -61,7 +61,7 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
|
|||
let types = (|| {
|
||||
let id = self.root.span().id()?;
|
||||
let src = self.ctx.source_by_id(id).ok()?;
|
||||
self.ctx.type_check(src)
|
||||
self.ctx.type_check(&src)
|
||||
})();
|
||||
let types = types.as_ref();
|
||||
|
||||
|
@ -462,7 +462,7 @@ fn describe_value(ctx: &mut AnalysisContext, v: &Value) -> EcoString {
|
|||
f = &with_f.0;
|
||||
}
|
||||
|
||||
let sig = analyze_dyn_signature(ctx, f.clone());
|
||||
let sig = ctx.signature_dyn(f.clone());
|
||||
sig.primary()
|
||||
.ty()
|
||||
.describe()
|
||||
|
@ -580,7 +580,7 @@ pub fn param_completions<'a>(
|
|||
let pos_index =
|
||||
param_index_at_leaf(&ctx.leaf, &func, args).map(|i| if this.is_some() { i + 1 } else { i });
|
||||
|
||||
let signature = analyze_dyn_signature(ctx.ctx, func.clone());
|
||||
let signature = ctx.ctx.signature_dyn(func.clone());
|
||||
|
||||
let leaf_type = ctx.ctx.literal_type_of_node(ctx.leaf.clone());
|
||||
log::debug!("pos_param_completion_by_type: {:?}", leaf_type);
|
||||
|
@ -601,7 +601,7 @@ pub fn param_completions<'a>(
|
|||
log::debug!("pos_param_completion_to: {:?}", pos);
|
||||
|
||||
if let Some(pos) = pos {
|
||||
if set && !pos.settable {
|
||||
if set && !pos.attrs.settable {
|
||||
break 'pos_check;
|
||||
}
|
||||
|
||||
|
@ -609,7 +609,7 @@ pub fn param_completions<'a>(
|
|||
doc = Some(plain_docs_sentence(docs));
|
||||
}
|
||||
|
||||
if pos.positional {
|
||||
if pos.attrs.positional {
|
||||
type_completion(ctx, &pos.ty, doc.as_deref());
|
||||
}
|
||||
}
|
||||
|
@ -627,10 +627,10 @@ pub fn param_completions<'a>(
|
|||
}
|
||||
log::debug!(
|
||||
"pos_named_param_completion_to({set:?}): {name:?} {:?}",
|
||||
param.settable
|
||||
param.attrs.settable
|
||||
);
|
||||
|
||||
if set && !param.settable {
|
||||
if set && !param.attrs.settable {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -640,7 +640,7 @@ pub fn param_completions<'a>(
|
|||
.clone()
|
||||
};
|
||||
|
||||
if param.named {
|
||||
if param.attrs.named {
|
||||
let compl = Completion {
|
||||
kind: CompletionKind::Field,
|
||||
label: param.name.as_ref().into(),
|
||||
|
@ -679,7 +679,7 @@ pub fn param_completions<'a>(
|
|||
ctx.completions.push(compl);
|
||||
}
|
||||
|
||||
if param.positional {
|
||||
if param.attrs.positional {
|
||||
type_completion(ctx, ¶m.ty, docs().as_deref());
|
||||
}
|
||||
}
|
||||
|
@ -986,14 +986,14 @@ pub fn named_param_value_completions<'a>(
|
|||
func = f.0.clone();
|
||||
}
|
||||
|
||||
let signature = analyze_dyn_signature(ctx.ctx, func.clone());
|
||||
let signature = ctx.ctx.signature_dyn(func.clone());
|
||||
|
||||
let primary_sig = signature.primary();
|
||||
|
||||
let Some(param) = primary_sig.get_named(name) else {
|
||||
return;
|
||||
};
|
||||
if !param.named {
|
||||
if !param.attrs.named {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue