diff --git a/crates/tinymist-query/src/adt/interner.rs b/crates/tinymist-query/src/adt/interner.rs index 3b02936a..30371f30 100644 --- a/crates/tinymist-query/src/adt/interner.rs +++ b/crates/tinymist-query/src/adt/interner.rs @@ -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 { } } +static EMPTY: LazyLock> = LazyLock::new(|| Interned::new_str("")); +impl Default for Interned { + fn default() -> Self { + EMPTY.clone() + } +} + impl From<&str> for Interned { fn from(s: &str) -> Self { Interned::new_str(s) @@ -249,6 +256,32 @@ impl PartialEq for Interned { impl Eq for Interned {} +impl serde::Serialize for Interned { + fn serialize(&self, serializer: S) -> Result { + self.arc.serialize(serializer) + } +} + +impl<'de> serde::Deserialize<'de> for Interned { + fn deserialize>(deserializer: D) -> Result { + struct StrVisitor; + + impl<'de> serde::de::Visitor<'de> for StrVisitor { + type Value = Interned; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string") + } + + fn visit_str(self, v: &str) -> Result { + Ok(Interned::new_str(v)) + } + } + + deserializer.deserialize_str(StrVisitor) + } +} + impl Hash for Interned { fn hash(&self, state: &mut H) { // NOTE: Cast disposes vtable pointer / slice/str length. diff --git a/crates/tinymist-query/src/analysis/call.rs b/crates/tinymist-query/src/analysis/call.rs index 813d9378..c4b9f0aa 100644 --- a/crates/tinymist-query/src/analysis/call.rs +++ b/crates/tinymist-query/src/analysis/call.rs @@ -73,7 +73,7 @@ pub fn analyze_call_no_cache( callee_node: LinkedNode, args: ast::Args<'_>, ) -> Option { - 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 { diff --git a/crates/tinymist-query/src/analysis/global.rs b/crates/tinymist-query/src/analysis/global.rs index 9fb64edf..2809e456 100644 --- a/crates/tinymist-query/src/analysis/global.rs +++ b/crates/tinymist-query/src/analysis/global.rs @@ -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 { + pub fn get_signature(&self, func: &SignatureTarget) -> Option { 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 { 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> { + pub(crate) fn type_check(&mut self, source: &Source) -> Option> { 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> { - 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 { - 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 { 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 { + self.type_check(source)?.type_of_span(s) } pub(crate) fn literal_type_of_node(&mut self, k: LinkedNode) -> Option { 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())) } diff --git a/crates/tinymist-query/src/analysis/post_tyck.rs b/crates/tinymist-query/src/analysis/post_tyck.rs index 4dcc06aa..f379e5b6 100644 --- a/crates/tinymist-query/src/analysis/post_tyck.rs +++ b/crates/tinymist-query/src/analysis/post_tyck.rs @@ -145,7 +145,7 @@ impl<'a, 'w> TyCtxMut for PostTypeCheckWorker<'a, 'w> { } fn type_of_func(&mut self, func: &Func) -> Option> { - self.ctx.type_of_func(func) + Some(self.ctx.signature_dyn(func.clone()).type_sig()) } } diff --git a/crates/tinymist-query/src/analysis/signature.rs b/crates/tinymist-query/src/analysis/signature.rs index 23f369c6..2fd30524 100644 --- a/crates/tinymist-query/src/analysis/signature.rs +++ b/crates/tinymist-query/src/analysis/signature.rs @@ -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, /// 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, /// 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, _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 { - 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 { + 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 { 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 { -// 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 { - 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 { let mut pos_tys = vec![]; let mut named_tys = Vec::new(); @@ -326,37 +382,26 @@ fn analyze_dyn_signature_inner(func: Func) -> Arc { 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 { 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 { 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>, 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>, 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>, add_param: &mut impl FnM docs: None, default: None, ty: Ty::Any, - positional: true, - named: false, - variadic: true, - settable: false, + attrs: ParamAttrs::variadic(), }); } } diff --git a/crates/tinymist-query/src/analysis/tyck.rs b/crates/tinymist-query/src/analysis/tyck.rs index 2e447f06..4efd6777 100644 --- a/crates/tinymist-query/src/analysis/tyck.rs +++ b/crates/tinymist-query/src/analysis/tyck.rs @@ -93,7 +93,7 @@ impl<'a, 'w> TyCtxMut for TypeChecker<'a, 'w> { } fn type_of_func(&mut self, func: &Func) -> Option> { - 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 { diff --git a/crates/tinymist-query/src/analysis/tyck/docs.rs b/crates/tinymist-query/src/analysis/tyck/docs.rs index dfff14b5..1902dc98 100644 --- a/crates/tinymist-query/src/analysis/tyck/docs.rs +++ b/crates/tinymist-query/src/analysis/tyck/docs.rs @@ -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> { - let closure = root.cast::()?; - 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> { let lb = root.cast::()?; 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))) } } diff --git a/crates/tinymist-query/src/analysis/tyck/syntax.rs b/crates/tinymist-query/src/analysis/tyck/syntax.rs index ce3f55d8..96c7742e 100644 --- a/crates/tinymist-query/src/analysis/tyck/syntax.rs +++ b/crates/tinymist-query/src/analysis/tyck/syntax.rs @@ -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 = LazyLock::new(DocString::default); +static EMPTY_VAR_DOC: LazyLock = LazyLock::new(VarDoc::default); impl<'a, 'w> TypeChecker<'a, 'w> { pub(crate) fn check_syntax(&mut self, root: LinkedNode) -> Option { @@ -374,12 +379,20 @@ impl<'a, 'w> TypeChecker<'a, 'w> { } fn check_closure(&mut self, root: LinkedNode<'_>) -> Option { - 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 { diff --git a/crates/tinymist-query/src/completion.rs b/crates/tinymist-query/src/completion.rs index 429a7eb9..912a5f56 100644 --- a/crates/tinymist-query/src/completion.rs +++ b/crates/tinymist-query/src/completion.rs @@ -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:?}"); diff --git a/crates/tinymist-query/src/docs/package.rs b/crates/tinymist-query/src/docs/package.rs index 3f0a123b..9efcf4c7 100644 --- a/crates/tinymist-query/src/docs/package.rs +++ b/crates/tinymist-query/src/docs/package.rs @@ -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(); diff --git a/crates/tinymist-query/src/docs/symbol.rs b/crates/tinymist-query/src/docs/symbol.rs index 6df60f49..855937e6 100644 --- a/crates/tinymist-query/src/docs/symbol.rs +++ b/crates/tinymist-query/src/docs/symbol.rs @@ -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; + /// Documentation about a symbol. #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "kind")] -pub enum SymbolDocs { +pub enum SymbolDocsT { /// Documentation about a function. #[serde(rename = "func")] - Function(Box), + Function(Box>), /// Documentation about a variable. #[serde(rename = "var")] Variable(TidyVarDocs), @@ -75,14 +81,14 @@ pub enum SymbolDocs { }, } -impl SymbolDocs { +impl SymbolDocsT { /// 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 { /// Documentation for the function. pub docs: EcoString, - // pub return_ty: Option, - // pub params: Vec, /// The positional parameters. - pub pos: Vec, + pub pos: Vec>, /// The named parameters. - pub named: BTreeMap, + pub named: BTreeMap, ParamDocsT>, /// The rest parameter. - pub rest: Option, + pub rest: Option>, /// The return type. - pub ret_ty: TypeRepr, + pub ret_ty: T, } +/// Documentation about a signature. +pub type SignatureDocs = SignatureDocsT; + 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; + /// Describes a function parameter. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ParamDocs { +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct ParamDocsT { /// The parameter's name. - pub name: String, + pub name: Interned, /// 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, - /// 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, diff --git a/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin.typ.snap b/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin.typ.snap index 67601683..11a8c9a1 100644 --- a/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin.typ.snap +++ b/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin.typ.snap @@ -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" } + diff --git a/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin_poly.typ.snap b/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin_poly.typ.snap index 4600f47b..66d7eabd 100644 --- a/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin_poly.typ.snap +++ b/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin_poly.typ.snap @@ -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" } + diff --git a/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin_poly2.typ.snap b/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin_poly2.typ.snap index 8efac0c9..811739d9 100644 --- a/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin_poly2.typ.snap +++ b/crates/tinymist-query/src/fixtures/call_info/snaps/test@builtin_poly2.typ.snap @@ -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" } + diff --git a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named.typ.snap b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named.typ.snap index 06c95de2..92041d59 100644 --- a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named.typ.snap +++ b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named.typ.snap @@ -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" } + diff --git a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named_with.typ.snap b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named_with.typ.snap index 59a169cd..f8cf63f9 100644 --- a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named_with.typ.snap +++ b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named_with.typ.snap @@ -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" } + diff --git a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named_with2.typ.snap b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named_with2.typ.snap index 588fd9ff..894f8535 100644 --- a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named_with2.typ.snap +++ b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_named_with2.typ.snap @@ -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" } + diff --git a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_with.typ.snap b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_with.typ.snap index 641f0b95..ab9b193f 100644 --- a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_with.typ.snap +++ b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_with.typ.snap @@ -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" } + diff --git a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_with2.typ.snap b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_with2.typ.snap index 976ebbfd..948411b5 100644 --- a/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_with2.typ.snap +++ b/crates/tinymist-query/src/fixtures/call_info/snaps/test@user_with2.typ.snap @@ -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 --- - + diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_var.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_var.typ.snap index 25f28150..00dbe7fa 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_var.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@annotation_var.typ.snap @@ -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 diff --git a/crates/tinymist-query/src/fixtures/type_check/snaps/test@tuple_map.typ.snap b/crates/tinymist-query/src/fixtures/type_check/snaps/test@tuple_map.typ.snap index 55b66cf2..5df1db06 100644 --- a/crates/tinymist-query/src/fixtures/type_check/snaps/test@tuple_map.typ.snap +++ b/crates/tinymist-query/src/fixtures/type_check/snaps/test@tuple_map.typ.snap @@ -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 diff --git a/crates/tinymist-query/src/signature_help.rs b/crates/tinymist-query/src/signature_help.rs index cc0015d3..da3fb6c2 100644 --- a/crates/tinymist-query/src/signature_help.rs +++ b/crates/tinymist-query/src/signature_help.rs @@ -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; } diff --git a/crates/tinymist-query/src/ty/bound.rs b/crates/tinymist-query/src/ty/bound.rs index eda06084..7be2d57c 100644 --- a/crates/tinymist-query/src/ty/bound.rs +++ b/crates/tinymist-query/src/ty/bound.rs @@ -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> { + let mut results = vec![]; + fn collect(ty: &Ty, results: &mut Vec>) { + 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); diff --git a/crates/tinymist-query/src/ty/def.rs b/crates/tinymist-query/src/ty/def.rs index 2283c2aa..f793f28c 100644 --- a/crates/tinymist-query/src/ty/def.rs +++ b/crates/tinymist-query/src/ty/def.rs @@ -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, /// The checked documentation of definitions - pub var_docs: HashMap>, + pub var_docs: HashMap>, /// The local binding of the type variable pub local_binds: snapshot_map::SnapshotMap, /// The typing on syntax structures diff --git a/crates/tinymist-query/src/upstream/complete/ext.rs b/crates/tinymist-query/src/upstream/complete/ext.rs index e4658b4e..f2d38268 100644 --- a/crates/tinymist-query/src/upstream/complete/ext.rs +++ b/crates/tinymist-query/src/upstream/complete/ext.rs @@ -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; } diff --git a/tests/e2e/main.rs b/tests/e2e/main.rs index b7802595..d4b4f985 100644 --- a/tests/e2e/main.rs +++ b/tests/e2e/main.rs @@ -385,7 +385,7 @@ fn e2e() { }); let hash = replay_log(&tinymist_binary, &root.join("vscode")); - insta::assert_snapshot!(hash, @"siphash128_13:c74f86e2e0fa2ecb0323814645f39c1b"); + insta::assert_snapshot!(hash, @"siphash128_13:925d0549a37fe091a774d04fce8614e4"); } }