feat: combine signature solving (#696)

* feat: combine signature solving

* dev: update snapshot

* dev: update snapshot
This commit is contained in:
Myriad-Dreamin 2024-10-17 18:45:52 +08:00 committed by GitHub
parent 6d62bffdeb
commit 39f343d536
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 69 additions and 133 deletions

View file

@ -19,8 +19,7 @@ use typst::{model::Document, text::Font};
use crate::analysis::prelude::*;
use crate::analysis::{
analyze_bib, analyze_expr_, analyze_import_, analyze_signature, post_type_check, BibInfo,
DefUseInfo, DefinitionLink, DocString, ImportInfo, PathPreference, Signature, SignatureTarget,
Ty, TypeScheme,
DefUseInfo, DocString, ImportInfo, PathPreference, Signature, SignatureTarget, Ty, TypeScheme,
};
use crate::docs::{DocStringKind, SignatureDocs};
use crate::syntax::{
@ -574,15 +573,8 @@ impl<'w> AnalysisContext<'w> {
res
}
pub(crate) fn signature_docs(
&mut self,
source: &Source,
def_ident: Option<&IdentRef>,
runtime_fn: &Value,
) -> Option<SignatureDocs> {
let def_use = self.def_use(source.clone())?;
let ty_chk = self.type_check(source)?;
crate::docs::signature_docs(self, Some(&(def_use, ty_chk)), def_ident, runtime_fn, None)
pub(crate) fn signature_docs(&mut self, runtime_fn: &Value) -> Option<SignatureDocs> {
crate::docs::signature_docs(self, runtime_fn, None)
}
pub(crate) fn compute_docstring(
@ -739,28 +731,6 @@ impl<'w> AnalysisContext<'w> {
self.type_of_span(rr.span())
}
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)?;
let def_use = self.def_use(source.clone())?;
let (def_id, _) = def_use.get_def(def_fid, def_ident)?;
ty_chk.type_of_def(def_id)
}
pub(crate) fn user_type_of_def(&mut self, source: &Source, def: &DefinitionLink) -> Option<Ty> {
let def_at = def.def_at.clone()?;
let def_ident = IdentRef {
name: def.name.clone(),
range: def_at.1,
};
self.user_type_of_ident(source, def_at.0, &def_ident)
}
pub(crate) fn type_of_span(&mut self, s: Span) -> Option<Ty> {
let id = s.id()?;
let source = self.source_by_id(id).ok()?;

View file

@ -13,18 +13,11 @@ use crate::syntax::{get_check_target, get_check_target_by_context, CheckTarget,
/// With given type information, check the type of a literal expression again by
/// touching the possible related nodes.
pub(crate) fn post_type_check(
_ctx: &mut AnalysisContext,
ctx: &mut AnalysisContext,
info: &TypeScheme,
node: LinkedNode,
) -> Option<Ty> {
let mut worker = PostTypeCheckWorker {
ctx: _ctx,
checked: HashMap::new(),
locals: TypeScheme::default(),
info,
};
worker.check(&node)
PostTypeChecker::new(ctx, info).check(&node)
}
#[derive(Default)]
@ -54,7 +47,7 @@ impl SignatureReceiver {
fn check_signature<'a>(
receiver: &'a mut SignatureReceiver,
target: &'a ParamTarget,
) -> impl FnMut(&mut PostTypeCheckWorker, Sig, &[Interned<ArgsTy>], bool) -> Option<()> + 'a {
) -> impl FnMut(&mut PostTypeChecker, Sig, &[Interned<ArgsTy>], bool) -> Option<()> + 'a {
move |worker, sig, args, pol| {
let SigShape { sig: sig_ins, .. } = sig.shape(worker)?;
@ -99,16 +92,14 @@ fn check_signature<'a>(
}
}
// #[derive(BindTyCtx)]
// #[bind(info)]
struct PostTypeCheckWorker<'a, 'w> {
pub(crate) struct PostTypeChecker<'a, 'w> {
ctx: &'a mut AnalysisContext<'w>,
checked: HashMap<Span, Option<Ty>>,
info: &'a TypeScheme,
checked: HashMap<Span, Option<Ty>>,
locals: TypeScheme,
}
impl<'a, 'w> TyCtx for PostTypeCheckWorker<'a, 'w> {
impl<'a, 'w> TyCtx for PostTypeChecker<'a, 'w> {
fn global_bounds(&self, var: &Interned<TypeVar>, pol: bool) -> Option<TypeBounds> {
self.info.global_bounds(var, pol)
}
@ -118,7 +109,7 @@ impl<'a, 'w> TyCtx for PostTypeCheckWorker<'a, 'w> {
}
}
impl<'a, 'w> TyCtxMut for PostTypeCheckWorker<'a, 'w> {
impl<'a, 'w> TyCtxMut for PostTypeChecker<'a, 'w> {
type Snap = <TypeScheme as TyCtxMut>::Snap;
fn start_scope(&mut self) -> Self::Snap {
@ -142,7 +133,16 @@ impl<'a, 'w> TyCtxMut for PostTypeCheckWorker<'a, 'w> {
}
}
impl<'a, 'w> PostTypeCheckWorker<'a, 'w> {
impl<'a, 'w> PostTypeChecker<'a, 'w> {
pub fn new(ctx: &'a mut AnalysisContext<'w>, info: &'a TypeScheme) -> Self {
Self {
ctx,
info,
checked: HashMap::new(),
locals: TypeScheme::default(),
}
}
fn check(&mut self, node: &LinkedNode) -> Option<Ty> {
let span = node.span();
if let Some(ty) = self.checked.get(&span) {
@ -341,7 +341,7 @@ impl<'a, 'w> PostTypeCheckWorker<'a, 'w> {
trait PostSigChecker {
fn check(
&mut self,
checker: &mut PostTypeCheckWorker,
checker: &mut PostTypeChecker,
sig: Sig,
args: &[Interned<ArgsTy>],
pol: bool,
@ -350,11 +350,11 @@ trait PostSigChecker {
impl<T> PostSigChecker for T
where
T: FnMut(&mut PostTypeCheckWorker, Sig, &[Interned<ArgsTy>], bool) -> Option<()>,
T: FnMut(&mut PostTypeChecker, Sig, &[Interned<ArgsTy>], bool) -> Option<()>,
{
fn check(
&mut self,
checker: &mut PostTypeCheckWorker,
checker: &mut PostTypeChecker,
sig: Sig,
args: &[Interned<ArgsTy>],
pol: bool,
@ -365,7 +365,7 @@ where
#[derive(BindTyCtx)]
#[bind(0)]
struct PostSigCheckWorker<'x, 'a, 'w, T>(&'x mut PostTypeCheckWorker<'a, 'w>, &'x mut T);
struct PostSigCheckWorker<'x, 'a, 'w, T>(&'x mut PostTypeChecker<'a, 'w>, &'x mut T);
impl<'x, 'a, 'w, T: PostSigChecker> SigChecker for PostSigCheckWorker<'x, 'a, 'w, T> {
fn check(

View file

@ -3,6 +3,7 @@
use typst::foundations::{self, Closure, ParamInfo};
use super::{prelude::*, resolve_callee, BuiltinTy, SigTy, TypeSources};
use crate::analysis::PostTypeChecker;
use crate::docs::UntypedSymbolDocs;
use crate::syntax::get_non_strict_def_target;
use crate::upstream::truncated_repr;
@ -104,6 +105,13 @@ impl Signature {
}
}
/// Returns the all parameters of the function.
pub(crate) fn params(&self) -> impl Iterator<Item = (&ParamSpec, Option<&Ty>)> {
let primary = self.primary().params();
// todo: with stack
primary
}
pub(crate) fn type_sig(&self) -> Interned<SigTy> {
let primary = self.primary().sig_ty.clone();
// todo: with stack
@ -166,6 +174,22 @@ impl PrimarySignature {
self.has_spread_right()
.then(|| &self.param_specs[self.pos_size() + self.sig_ty.names.names.len()])
}
/// Returns the all parameters of the function.
pub fn params(&self) -> impl Iterator<Item = (&ParamSpec, Option<&Ty>)> {
let pos = self.pos();
let named = self.named();
let rest = self.rest();
let type_sig = &self.sig_ty;
let pos = pos
.iter()
.enumerate()
.map(|(i, pos)| (pos, type_sig.pos(i)));
let named = named.iter().map(|x| (x, type_sig.named(&x.name)));
let rest = rest.into_iter().map(|x| (x, type_sig.rest_param()));
pos.chain(named).chain(rest)
}
}
/// Describes a function argument instance
@ -247,7 +271,7 @@ fn analyze_type_signature(
let type_var = srcs.into_iter().next()?;
match type_var {
TypeSources::Var(v) => {
let sig_ty = ty.sig_repr(true)?;
let sig_ty = ty.sig_repr(true, &mut PostTypeChecker::new(ctx, &type_info))?;
let docstring = match type_info.var_docs.get(&v.def).map(|x| x.as_ref()) {
Some(UntypedSymbolDocs::Function(sig)) => sig,

View file

@ -13,7 +13,6 @@ use typst::syntax::{FileId, Span, VirtualPath};
use typst::World;
use crate::docs::{file_id_repr, module_docs, symbol_docs, SymbolDocs, SymbolsInfo};
use crate::syntax::IdentRef;
use crate::ty::Ty;
use crate::AnalysisContext;
@ -112,15 +111,6 @@ pub fn package_docs(
log::debug!("module: {primary} -- {parent_ident}");
let type_info = None.or_else(|| {
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)?;
Some((def_use, ty_chck))
});
let type_info = type_info.as_ref();
let persist_fid = fid.map(|f| file_ids.insert_full(f).0);
#[derive(Serialize)]
@ -157,15 +147,9 @@ pub fn package_docs(
});
sym.head.loc = span;
let def_ident = sym.head.name_range.as_ref().map(|range| IdentRef {
name: sym.head.name.clone(),
range: range.clone(),
});
let docs = symbol_docs(
ctx,
type_info,
sym.head.kind,
def_ident.as_ref(),
sym.head.value.as_ref(),
sym.head.docs.as_deref(),
Some(&mut doc_ty),

View file

@ -16,7 +16,6 @@ use typst::{
use super::tidy::*;
use crate::analysis::{ParamAttrs, ParamSpec};
use crate::docs::library;
use crate::syntax::IdentRef;
use crate::ty::Interned;
use crate::{ty::Ty, AnalysisContext};
@ -95,14 +94,12 @@ impl<T> SymbolDocsT<T> {
pub(crate) fn symbol_docs(
ctx: &mut AnalysisContext,
type_info: Option<&TypeInfo>,
kind: DocStringKind,
def_ident: Option<&IdentRef>,
sym_value: Option<&Value>,
docs: Option<&str>,
doc_ty: Option<ShowTypeRepr>,
) -> Result<SymbolDocs, String> {
let signature = sym_value.and_then(|e| signature_docs(ctx, type_info, def_ident, e, doc_ty));
let signature = sym_value.and_then(|e| signature_docs(ctx, e, doc_ty));
if let Some(signature) = signature {
return Ok(SymbolDocs::Function(Box::new(signature)));
}
@ -237,8 +234,6 @@ impl ParamDocs {
}
}
type TypeInfo = (Arc<crate::analysis::DefUseInfo>, Arc<crate::ty::TypeScheme>);
fn format_ty(ty: Option<&Ty>, doc_ty: Option<&mut ShowTypeRepr>) -> TypeRepr {
match doc_ty {
Some(doc_ty) => doc_ty(ty),
@ -250,8 +245,6 @@ fn format_ty(ty: Option<&Ty>, doc_ty: Option<&mut ShowTypeRepr>) -> TypeRepr {
pub(crate) fn signature_docs(
ctx: &mut AnalysisContext,
type_info: Option<&TypeInfo>,
def_ident: Option<&IdentRef>,
runtime_fn: &Value,
mut doc_ty: Option<ShowTypeRepr>,
) -> Option<SignatureDocs> {
@ -278,35 +271,22 @@ pub(crate) fn signature_docs(
}
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?)?;
Some(def_id)
});
let docstring = type_info.and_then(|(_, ty_chk)| ty_chk.var_docs.get(&def_id?));
let type_sig = type_info.and_then(|(_, ty_chk)| ty_chk.type_of_def(def_id?));
let type_sig = type_sig.and_then(|type_sig| type_sig.sig_repr(true));
let type_sig = sig.type_sig().clone();
let pos_in = sig
.primary()
.pos()
.iter()
.enumerate()
.map(|(i, pos)| (pos, type_sig.as_ref().and_then(|sig| sig.pos(i))));
.map(|(i, pos)| (pos, type_sig.pos(i)));
let named_in = sig
.primary()
.named()
.iter()
.map(|x| (x, type_sig.as_ref().and_then(|sig| sig.named(&x.name))));
let rest_in = sig
.primary()
.rest()
.map(|x| (x, type_sig.as_ref().and_then(|sig| sig.rest_param())));
.map(|x| (x, type_sig.named(&x.name)));
let rest_in = sig.primary().rest().map(|x| (x, type_sig.rest_param()));
let ret_in = type_sig
.as_ref()
.and_then(|sig| sig.body.as_ref())
.or_else(|| sig.primary().sig_ty.body.as_ref());
let ret_in = type_sig.body.as_ref();
let pos = pos_in
.map(|(param, ty)| ParamDocs::new(param, ty, doc_ty.as_mut()))
@ -324,7 +304,7 @@ pub(crate) fn signature_docs(
let ret_ty = format_ty(ret_in, doc_ty.as_mut());
Some(SignatureDocs {
docs: docstring.map(|x| x.docs().clone()).unwrap_or_default(),
docs: sig.primary().docs.clone().unwrap_or_default(),
pos,
named,
rest,

View file

@ -3,4 +3,5 @@ source: crates/tinymist-query/src/analysis.rs
expression: CallSnapshot(result.as_deref())
input_file: crates/tinymist-query/src/fixtures/call_info/user_named.typ
---
<nil>
y: 1 -> CallParamInfo { kind: Named, is_content_block: false, param_name: "y" }
1 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "x" }

View file

@ -4,6 +4,6 @@ expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/hover/annotate_fn.typ
---
{
"contents": "```typc\nlet touying-fn-wrapper(fn: (..: []) => any | function, ..args: arguments, max-repetitions: int | none = none, repetitions: int | none = none);\n```\n\n---\n\n\n #let fn = `(..fn-args) => any`;\n\n - fn (function, fn): The `fn`.\n - max-repetitions (int): The `max-repetitions`.\n - repetitions (int): The `repetitions`.\n - args (any, fn-args): The `args`.",
"contents": "```typc\nlet touying-fn-wrapper(fn, ..args, max-repetitions = none, repetitions = none);\n```\n\n---\n\n\n #let fn = `(..fn-args) => any`;\n\n - fn (function, fn): The `fn`.\n - max-repetitions (int): The `max-repetitions`.\n - repetitions (int): The `repetitions`.\n - args (any, fn-args): The `args`.",
"range": "8:20:8:38"
}

View file

@ -251,10 +251,7 @@ fn def_tooltip(
Some(LspHoverContents::Array(results))
}
LexicalKind::Var(LexicalVarKind::Function) => {
let sig = lnk
.value
.as_ref()
.and_then(|e| ctx.signature_docs(source, lnk.to_ident_ref().as_ref(), e));
let sig = lnk.value.as_ref().and_then(|e| ctx.signature_docs(e));
results.push(MarkedString::LanguageString(LanguageString {
language: "typc".to_owned(),

View file

@ -43,8 +43,6 @@ impl SemanticRequest for SignatureHelpRequest {
let def_link = find_definition(ctx, source.clone(), None, deref_target)?;
let type_sig = ctx.user_type_of_def(&source, &def_link);
let documentation = DocTooltip::get(ctx, &def_link)
.as_deref()
.map(markdown_docs);
@ -63,13 +61,8 @@ impl SemanticRequest for SignatureHelpRequest {
}
let sig = ctx.signature_dyn(function.clone());
let pos = sig.primary().pos();
let named = sig.primary().named();
let rest = sig.primary().rest();
let type_sig = type_sig.and_then(|type_sig| type_sig.sig_repr(true));
log::info!("got type signature {type_sig:?}");
log::debug!("got signature {sig:?}");
let mut active_parameter = None;
@ -77,20 +70,10 @@ impl SemanticRequest for SignatureHelpRequest {
let mut params = Vec::new();
label.push('(');
let pos = pos
.iter()
.enumerate()
.map(|(i, pos)| (pos, type_sig.as_ref().and_then(|sig| sig.pos(i))));
let named = named
.iter()
.map(|x| (x, type_sig.as_ref().and_then(|sig| sig.named(&x.name))));
let rest = rest
.into_iter()
.map(|x| (x, type_sig.as_ref().and_then(|sig| sig.rest_param())));
let mut real_offset = 0;
let focus_name = OnceCell::new();
for (i, (param, ty)) in pos.chain(named).chain(rest).enumerate() {
for (i, (param, ty)) in sig.params().enumerate() {
if is_set && !param.attrs.settable {
continue;
}
@ -137,10 +120,7 @@ impl SemanticRequest for SignatureHelpRequest {
});
}
label.push(')');
let ret = type_sig
.as_ref()
.and_then(|sig| sig.body.as_ref())
.or_else(|| sig.primary().sig_ty.body.as_ref());
let ret = sig.type_sig().body.clone();
if let Some(ret_ty) = ret {
label.push_str(" -> ");
label.push_str(ret_ty.describe().as_deref().unwrap_or("any"));

View file

@ -97,7 +97,7 @@ impl Ty {
}
/// Get the signature representation of the given type.
pub fn sig_repr(&self, pol: bool) -> Option<Interned<SigTy>> {
pub fn sig_repr(&self, pol: bool, ctx: &mut impl TyCtxMut) -> Option<Interned<SigTy>> {
// todo: union sig
// let mut pos = vec![];
// let mut named = HashMap::new();
@ -108,12 +108,12 @@ impl Ty {
#[derive(BindTyCtx)]
#[bind(0)]
struct SigReprDriver<'a, C: TyCtx>(&'a C, &'a mut Option<Interned<SigTy>>);
struct SigReprDriver<'a, C: TyCtxMut>(&'a mut C, &'a mut Option<Interned<SigTy>>);
impl<C: TyCtx> SigChecker for SigReprDriver<'_, C> {
impl<C: TyCtxMut> SigChecker for SigReprDriver<'_, C> {
fn check(&mut self, sig: Sig, _ctx: &mut SigCheckContext, _pol: bool) -> Option<()> {
// todo: bind type context
let sig = sig.shape(&mut ())?;
let sig = sig.shape(self.0)?;
*self.1 = Some(sig.sig.clone());
Some(())
}
@ -123,7 +123,7 @@ impl Ty {
pol,
SigSurfaceKind::Call,
// todo: bind type context
&mut SigReprDriver(&(), &mut primary),
&mut SigReprDriver(ctx, &mut primary),
);
primary