mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-11-24 05:06:41 +00:00
refactor: change PrimarySignature structure to merge type checking info (#687)
* dev: support spread left params * dev: stage merge * dev: remove ParamSpecShort * chore: remove useless code * dev: merge all things back * fix: testing * fix: testing * remove: useless method
This commit is contained in:
parent
1f5be314a7
commit
a3f100e7cb
22 changed files with 260 additions and 218 deletions
|
|
@ -449,14 +449,18 @@ mod signature_tests {
|
|||
};
|
||||
|
||||
writeln!(f, "fn(")?;
|
||||
for param in primary_sig.pos.iter() {
|
||||
for param in primary_sig.pos() {
|
||||
writeln!(f, " {},", param.name)?;
|
||||
}
|
||||
for (name, param) in primary_sig.named.iter() {
|
||||
writeln!(f, " {}: {},", name, param.expr.clone().unwrap_or_default())?;
|
||||
for param in primary_sig.named() {
|
||||
if let Some(expr) = ¶m.default {
|
||||
writeln!(f, " {}: {},", param.name, expr)?;
|
||||
} else {
|
||||
writeln!(f, " {},", param.name)?;
|
||||
}
|
||||
if let Some(primary_sig) = &primary_sig.rest {
|
||||
writeln!(f, " ...{}, ", primary_sig.name)?;
|
||||
}
|
||||
if let Some(param) = primary_sig.rest() {
|
||||
writeln!(f, " ...{}, ", param.name)?;
|
||||
}
|
||||
write!(f, ")")?;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use typst::syntax::SyntaxNode;
|
||||
|
||||
use super::{ParamSpec, Signature};
|
||||
use super::{Signature, StrRef};
|
||||
use crate::{
|
||||
analysis::{analyze_signature, PrimarySignature, SignatureTarget},
|
||||
prelude::*,
|
||||
|
|
@ -26,9 +26,8 @@ pub struct CallParamInfo {
|
|||
pub kind: ParamKind,
|
||||
/// Whether the parameter is a content block.
|
||||
pub is_content_block: bool,
|
||||
/// The parameter's specification.
|
||||
pub param: Arc<ParamSpec>,
|
||||
// types: EcoVec<()>,
|
||||
/// The name of the parameter.
|
||||
pub param_name: StrRef,
|
||||
}
|
||||
|
||||
/// Describes a function call.
|
||||
|
|
@ -99,9 +98,9 @@ pub fn analyze_call_no_cache(
|
|||
fn advance(&mut self, info: &mut CallInfo, arg: Option<SyntaxNode>) {
|
||||
let (kind, param) = match self.state {
|
||||
PosState::Init => {
|
||||
if !self.signature.pos.is_empty() {
|
||||
if !self.signature.pos().is_empty() {
|
||||
self.state = PosState::Pos(0);
|
||||
} else if self.signature.rest.is_some() {
|
||||
} else if self.signature.has_spread_right() {
|
||||
self.state = PosState::Variadic;
|
||||
} else {
|
||||
self.state = PosState::Final;
|
||||
|
|
@ -110,17 +109,17 @@ pub fn analyze_call_no_cache(
|
|||
return;
|
||||
}
|
||||
PosState::Pos(i) => {
|
||||
if i + 1 < self.signature.pos.len() {
|
||||
if i + 1 < self.signature.pos_size() {
|
||||
self.state = PosState::Pos(i + 1);
|
||||
} else if self.signature.rest.is_some() {
|
||||
} else if self.signature.has_spread_right() {
|
||||
self.state = PosState::Variadic;
|
||||
} else {
|
||||
self.state = PosState::Final;
|
||||
}
|
||||
|
||||
(ParamKind::Positional, &self.signature.pos[i])
|
||||
(ParamKind::Positional, self.signature.get_pos(i).unwrap())
|
||||
}
|
||||
PosState::Variadic => (ParamKind::Rest, self.signature.rest.as_ref().unwrap()),
|
||||
PosState::Variadic => (ParamKind::Rest, self.signature.rest().unwrap()),
|
||||
PosState::Final => return,
|
||||
};
|
||||
|
||||
|
|
@ -132,8 +131,7 @@ pub fn analyze_call_no_cache(
|
|||
CallParamInfo {
|
||||
kind,
|
||||
is_content_block,
|
||||
param: param.clone(),
|
||||
// types: eco_vec![],
|
||||
param_name: param.name.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -144,7 +142,7 @@ pub fn analyze_call_no_cache(
|
|||
PosState::Init => unreachable!(),
|
||||
// todo: not precise
|
||||
PosState::Pos(..) => {
|
||||
if self.signature.rest.is_some() {
|
||||
if self.signature.has_spread_right() {
|
||||
self.state = PosState::Variadic;
|
||||
} else {
|
||||
self.state = PosState::Final;
|
||||
|
|
@ -154,7 +152,7 @@ pub fn analyze_call_no_cache(
|
|||
PosState::Final => return,
|
||||
};
|
||||
|
||||
let Some(rest) = self.signature.rest.as_ref() else {
|
||||
let Some(rest) = self.signature.rest() else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -166,8 +164,7 @@ pub fn analyze_call_no_cache(
|
|||
CallParamInfo {
|
||||
kind: ParamKind::Rest,
|
||||
is_content_block,
|
||||
param: rest.clone(),
|
||||
// types: eco_vec![],
|
||||
param_name: rest.name.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -212,14 +209,13 @@ pub fn analyze_call_no_cache(
|
|||
ast::Arg::Named(named) => {
|
||||
let n = named.name().get().into();
|
||||
|
||||
if let Some(param) = signature.primary().named.get(&n) {
|
||||
if let Some(param) = signature.primary().get_named(&n) {
|
||||
info.arg_mapping.insert(
|
||||
arg_tag,
|
||||
CallParamInfo {
|
||||
kind: ParamKind::Named,
|
||||
is_content_block: false,
|
||||
param: param.clone(),
|
||||
// types: eco_vec![],
|
||||
param_name: param.name.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -463,6 +463,15 @@ impl<'w> AnalysisContext<'w> {
|
|||
/// Get the signature of a function.
|
||||
pub fn signature(&self, func: &SignatureTarget) -> Option<Signature> {
|
||||
match func {
|
||||
SignatureTarget::Def(source, r) => {
|
||||
// todo: check performance on peeking signature source frequently
|
||||
let cache_key = (source, r.range.start);
|
||||
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());
|
||||
|
|
@ -488,6 +497,16 @@ impl<'w> AnalysisContext<'w> {
|
|||
compute: impl FnOnce() -> Signature,
|
||||
) -> Signature {
|
||||
match func {
|
||||
SignatureTarget::Def(source, r) => {
|
||||
let cache_key = (source, r.range.start);
|
||||
let h = hash128(&cache_key);
|
||||
let slot = self.analysis.caches.static_signatures.entry(h);
|
||||
let slot = slot.or_insert_with(|| {
|
||||
let sig = compute();
|
||||
(self.lifetime, cache_key.0, cache_key.1, sig)
|
||||
});
|
||||
slot.3.clone()
|
||||
}
|
||||
SignatureTarget::Syntax(source, node) => {
|
||||
let cache_key = (source, node.offset());
|
||||
self.analysis
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
//! Analysis of function signatures.
|
||||
use core::fmt;
|
||||
use std::{borrow::Cow, collections::HashMap, ops::Range, sync::Arc};
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use ecow::{eco_vec, EcoString, EcoVec};
|
||||
use log::trace;
|
||||
use typst::syntax::{FileId as TypstFileId, Source};
|
||||
use ecow::{eco_format, eco_vec, EcoString, EcoVec};
|
||||
use typst::syntax::Source;
|
||||
use typst::{
|
||||
foundations::{Closure, Func, ParamInfo, Value},
|
||||
foundations::{Closure, Func, Value},
|
||||
syntax::{
|
||||
ast::{self, AstNode},
|
||||
LinkedNode, Span, SyntaxKind,
|
||||
LinkedNode, SyntaxKind,
|
||||
},
|
||||
};
|
||||
use typst_shim::syntax::LinkedNodeExt;
|
||||
|
|
@ -22,21 +22,19 @@ use crate::ty::SigTy;
|
|||
use crate::upstream::truncated_repr;
|
||||
use crate::AnalysisContext;
|
||||
|
||||
use super::{find_definition, DefinitionLink, LexicalKind, LexicalVarKind, Ty};
|
||||
|
||||
// pub fn analyze_signature
|
||||
use super::{find_definition, DefinitionLink, IdentRef, LexicalKind, LexicalVarKind, StrRef, Ty};
|
||||
|
||||
/// Describes a function parameter.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ParamSpec {
|
||||
/// The parameter's name.
|
||||
pub name: Interned<str>,
|
||||
/// Documentation for the parameter.
|
||||
pub docs: Cow<'static, str>,
|
||||
/// Inferred type of the parameter.
|
||||
pub(crate) base_type: Ty,
|
||||
/// The parameter's default name as value.
|
||||
pub expr: Option<EcoString>,
|
||||
/// The name of the parameter.
|
||||
pub name: StrRef,
|
||||
/// The docstring of the parameter.
|
||||
pub docs: Option<EcoString>,
|
||||
/// The default value of the variable
|
||||
pub default: Option<EcoString>,
|
||||
/// The type of the parameter.
|
||||
pub ty: Ty,
|
||||
/// Is the parameter positional?
|
||||
pub positional: bool,
|
||||
/// Is the parameter named?
|
||||
|
|
@ -50,21 +48,6 @@ pub struct ParamSpec {
|
|||
pub settable: bool,
|
||||
}
|
||||
|
||||
impl ParamSpec {
|
||||
fn from_static(f: &Func, p: &ParamInfo) -> Arc<Self> {
|
||||
Arc::new(Self {
|
||||
name: p.name.into(),
|
||||
docs: Cow::Borrowed(p.docs),
|
||||
base_type: Ty::from_param_site(f, p),
|
||||
expr: p.default.map(|d| truncated_repr(&d())),
|
||||
positional: p.positional,
|
||||
named: p.named,
|
||||
variadic: p.variadic,
|
||||
settable: p.settable,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes a function signature.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Signature {
|
||||
|
|
@ -101,16 +84,12 @@ impl Signature {
|
|||
/// Describes a primary function signature.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PrimarySignature {
|
||||
/// The positional parameters.
|
||||
pub pos: Vec<Arc<ParamSpec>>,
|
||||
/// The named parameters.
|
||||
pub named: HashMap<Interned<str>, Arc<ParamSpec>>,
|
||||
/// The documentation of the function
|
||||
pub docs: Option<EcoString>,
|
||||
/// The documentation of the parameter.
|
||||
pub param_specs: Vec<ParamSpec>,
|
||||
/// Whether the function has fill, stroke, or size parameters.
|
||||
pub has_fill_or_size_or_stroke: bool,
|
||||
/// The rest parameter.
|
||||
pub rest: Option<Arc<ParamSpec>>,
|
||||
/// The return type.
|
||||
pub(crate) ret_ty: Option<Ty>,
|
||||
/// The signature type.
|
||||
pub(crate) sig_ty: Interned<SigTy>,
|
||||
_broken: bool,
|
||||
|
|
@ -121,6 +100,42 @@ impl PrimarySignature {
|
|||
pub(crate) fn ty(&self) -> Ty {
|
||||
Ty::Func(self.sig_ty.clone())
|
||||
}
|
||||
|
||||
/// Returns the number of positional parameters of the function.
|
||||
pub fn pos_size(&self) -> usize {
|
||||
self.sig_ty.name_started as usize
|
||||
}
|
||||
|
||||
/// Returns the positional parameters of the function.
|
||||
pub fn pos(&self) -> &[ParamSpec] {
|
||||
&self.param_specs[..self.pos_size()]
|
||||
}
|
||||
|
||||
/// Returns the positional parameters of the function.
|
||||
pub fn get_pos(&self, offset: usize) -> Option<&ParamSpec> {
|
||||
self.pos().get(offset)
|
||||
}
|
||||
|
||||
/// Returns the named parameters of the function.
|
||||
pub fn named(&self) -> &[ParamSpec] {
|
||||
&self.param_specs[self.pos_size()..self.pos_size() + self.sig_ty.names.names.len()]
|
||||
}
|
||||
|
||||
/// Returns the named parameters of the function.
|
||||
pub fn get_named(&self, name: &StrRef) -> Option<&ParamSpec> {
|
||||
self.named().get(self.sig_ty.names.find(name)?)
|
||||
}
|
||||
|
||||
/// Returns the name of the rest parameter of the function.
|
||||
pub fn has_spread_right(&self) -> bool {
|
||||
self.sig_ty.spread_right
|
||||
}
|
||||
|
||||
/// Returns the rest parameter of the function.
|
||||
pub fn rest(&self) -> Option<&ParamSpec> {
|
||||
self.has_spread_right()
|
||||
.then(|| &self.param_specs[self.pos_size() + self.sig_ty.names.names.len()])
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes a function argument instance
|
||||
|
|
@ -132,20 +147,9 @@ pub struct ArgInfo {
|
|||
pub value: Option<Value>,
|
||||
}
|
||||
|
||||
/// Describes a span.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SpanInfo {
|
||||
/// Unresolved raw span
|
||||
Span(Span),
|
||||
/// Resolved span
|
||||
Range((TypstFileId, Range<usize>)),
|
||||
}
|
||||
|
||||
/// Describes a function argument list.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ArgsInfo {
|
||||
/// The span of the argument list.
|
||||
pub span: Option<SpanInfo>,
|
||||
/// The arguments.
|
||||
pub items: EcoVec<ArgInfo>,
|
||||
}
|
||||
|
|
@ -161,6 +165,8 @@ pub struct PartialSignature {
|
|||
|
||||
/// The language object that the signature is being analyzed for.
|
||||
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.
|
||||
Syntax(Source, LinkedNode<'a>),
|
||||
/// A function that is known at runtime.
|
||||
|
|
@ -182,6 +188,7 @@ pub(crate) fn analyze_signature(
|
|||
}
|
||||
|
||||
let func = match callee_node {
|
||||
SignatureTarget::Def(..) => todo!(),
|
||||
SignatureTarget::Syntax(source, node) => {
|
||||
let _ = resolve_callee_v2;
|
||||
let _ = source;
|
||||
|
|
@ -210,7 +217,6 @@ pub(crate) fn analyze_signature(
|
|||
let mut func = func;
|
||||
while let Repr::With(f) = func.inner() {
|
||||
with_stack.push(ArgsInfo {
|
||||
span: None,
|
||||
items: f
|
||||
.1
|
||||
.items
|
||||
|
|
@ -230,7 +236,7 @@ pub(crate) fn analyze_signature(
|
|||
})
|
||||
.primary()
|
||||
.clone();
|
||||
trace!("got signature {signature:?}");
|
||||
log::trace!("got signature {signature:?}");
|
||||
|
||||
if with_stack.is_empty() {
|
||||
return Some(Signature::Primary(signature));
|
||||
|
|
@ -311,32 +317,21 @@ fn resolve_callee_v2(
|
|||
}
|
||||
|
||||
fn analyze_dyn_signature_inner(func: Func) -> Arc<PrimarySignature> {
|
||||
use typst::foundations::func::Repr;
|
||||
let (params, ret_ty) = match func.inner() {
|
||||
Repr::With(..) => unreachable!(),
|
||||
Repr::Closure(c) => (analyze_closure_signature(c.clone()), None),
|
||||
Repr::Element(..) | Repr::Native(..) => {
|
||||
let ret_ty = func.returns().map(|r| Ty::from_return_site(&func, r));
|
||||
let params = func.params().unwrap();
|
||||
(
|
||||
params
|
||||
.iter()
|
||||
.map(|p| ParamSpec::from_static(&func, p))
|
||||
.collect(),
|
||||
ret_ty,
|
||||
)
|
||||
}
|
||||
};
|
||||
let mut pos_tys = vec![];
|
||||
let mut named_tys = Vec::new();
|
||||
let mut rest_ty = None;
|
||||
|
||||
let mut named_specs = BTreeMap::new();
|
||||
let mut param_specs = Vec::new();
|
||||
let mut rest_spec = None;
|
||||
|
||||
let mut pos = vec![];
|
||||
let mut named = HashMap::new();
|
||||
let mut rest = None;
|
||||
let mut broken = false;
|
||||
let mut has_fill = false;
|
||||
let mut has_stroke = false;
|
||||
let mut has_size = false;
|
||||
|
||||
for param in params.into_iter() {
|
||||
let mut add_param = |param: ParamSpec| {
|
||||
let name = param.name.clone();
|
||||
if param.named {
|
||||
match param.name.as_ref() {
|
||||
"fill" => {
|
||||
|
|
@ -350,103 +345,120 @@ fn analyze_dyn_signature_inner(func: Func) -> Arc<PrimarySignature> {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
named.insert(param.name.clone(), param.clone());
|
||||
named_tys.push((name.clone(), param.ty.clone()));
|
||||
named_specs.insert(name.clone(), param.clone());
|
||||
}
|
||||
|
||||
if param.variadic {
|
||||
if rest.is_some() {
|
||||
if rest_ty.is_some() {
|
||||
broken = true;
|
||||
} else {
|
||||
rest = Some(param.clone());
|
||||
rest_ty = Some(param.ty.clone());
|
||||
rest_spec = Some(param);
|
||||
}
|
||||
} else if param.positional {
|
||||
pos.push(param);
|
||||
// todo: we have some params that are both positional and named
|
||||
pos_tys.push(param.ty.clone());
|
||||
param_specs.push(param);
|
||||
}
|
||||
};
|
||||
|
||||
use typst::foundations::func::Repr;
|
||||
let ret_ty = match func.inner() {
|
||||
Repr::With(..) => unreachable!(),
|
||||
Repr::Closure(c) => {
|
||||
analyze_closure_signature(c.clone(), &mut add_param);
|
||||
None
|
||||
}
|
||||
Repr::Element(..) | Repr::Native(..) => {
|
||||
for p in func.params().unwrap() {
|
||||
add_param(ParamSpec {
|
||||
name: p.name.into(),
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
||||
let mut named_vec: Vec<(Interned<str>, Ty)> = named
|
||||
.iter()
|
||||
.map(|e| (e.0.clone(), e.1.base_type.clone()))
|
||||
.collect::<Vec<_>>();
|
||||
func.returns().map(|r| Ty::from_return_site(&func, r))
|
||||
}
|
||||
};
|
||||
|
||||
named_vec.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
let sig_ty = SigTy::new(pos_tys.into_iter(), named_tys, None, rest_ty, ret_ty);
|
||||
|
||||
for name in &sig_ty.names.names {
|
||||
param_specs.push(named_specs.get(name).unwrap().clone());
|
||||
}
|
||||
if let Some(doc) = rest_spec {
|
||||
param_specs.push(doc);
|
||||
}
|
||||
|
||||
let sig_ty = SigTy::new(
|
||||
pos.iter().map(|e| e.base_type.clone()),
|
||||
named_vec,
|
||||
rest.as_ref().map(|e| e.base_type.clone()),
|
||||
ret_ty.clone(),
|
||||
);
|
||||
Arc::new(PrimarySignature {
|
||||
pos,
|
||||
named,
|
||||
rest,
|
||||
ret_ty,
|
||||
docs: func.docs().map(From::from),
|
||||
param_specs,
|
||||
has_fill_or_size_or_stroke: has_fill || has_stroke || has_size,
|
||||
sig_ty: sig_ty.into(),
|
||||
_broken: broken,
|
||||
})
|
||||
}
|
||||
|
||||
fn analyze_closure_signature(c: Arc<LazyHash<Closure>>) -> Vec<Arc<ParamSpec>> {
|
||||
let mut params = vec![];
|
||||
|
||||
trace!("closure signature for: {:?}", c.node.kind());
|
||||
fn analyze_closure_signature(c: Arc<LazyHash<Closure>>, add_param: &mut impl FnMut(ParamSpec)) {
|
||||
log::trace!("closure signature for: {:?}", c.node.kind());
|
||||
|
||||
let closure = &c.node;
|
||||
let closure_ast = match closure.kind() {
|
||||
SyntaxKind::Closure => closure.cast::<ast::Closure>().unwrap(),
|
||||
_ => return params,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
for param in closure_ast.params().children() {
|
||||
match param {
|
||||
ast::Param::Pos(e) => {
|
||||
let name = format!("{}", PatternDisplay(&e));
|
||||
|
||||
params.push(Arc::new(ParamSpec {
|
||||
add_param(ParamSpec {
|
||||
name: name.as_str().into(),
|
||||
base_type: Ty::Any,
|
||||
// type_repr: None,
|
||||
expr: None,
|
||||
docs: None,
|
||||
default: None,
|
||||
ty: Ty::Any,
|
||||
positional: true,
|
||||
named: false,
|
||||
variadic: false,
|
||||
settable: false,
|
||||
docs: Cow::Borrowed(""),
|
||||
}));
|
||||
});
|
||||
}
|
||||
// todo: pattern
|
||||
ast::Param::Named(n) => {
|
||||
let expr = unwrap_expr(n.expr()).to_untyped().clone().into_text();
|
||||
params.push(Arc::new(ParamSpec {
|
||||
name: n.name().into(),
|
||||
base_type: Ty::Any,
|
||||
expr: Some(expr.clone()),
|
||||
add_param(ParamSpec {
|
||||
name: n.name().get().into(),
|
||||
docs: Some(eco_format!("Default value: {expr}")),
|
||||
default: Some(expr),
|
||||
ty: Ty::Any,
|
||||
positional: false,
|
||||
named: true,
|
||||
variadic: false,
|
||||
settable: true,
|
||||
docs: Cow::Owned("Default value: ".to_owned() + expr.as_str()),
|
||||
}));
|
||||
});
|
||||
}
|
||||
ast::Param::Spread(n) => {
|
||||
let ident = n.sink_ident().map(|e| e.as_str());
|
||||
params.push(Arc::new(ParamSpec {
|
||||
add_param(ParamSpec {
|
||||
name: ident.unwrap_or_default().into(),
|
||||
base_type: Ty::Any,
|
||||
expr: None,
|
||||
docs: None,
|
||||
default: None,
|
||||
ty: Ty::Any,
|
||||
positional: true,
|
||||
named: false,
|
||||
variadic: true,
|
||||
settable: false,
|
||||
docs: Cow::Borrowed(""),
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
params
|
||||
}
|
||||
|
||||
struct PatternDisplay<'a>(&'a ast::Pattern<'a>);
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ impl<'a, 'w> DocsChecker<'a, 'w> {
|
|||
}
|
||||
|
||||
let body = self.check_type_expr(m, c.body())?;
|
||||
let sig = SigTy::new(pos, named, rest, Some(body)).into();
|
||||
let sig = SigTy::new(pos.into_iter(), named, None, rest, Some(body)).into();
|
||||
|
||||
Some(Ty::Func(sig))
|
||||
});
|
||||
|
|
|
|||
|
|
@ -368,7 +368,7 @@ impl<'a, 'w> TypeChecker<'a, 'w> {
|
|||
}
|
||||
}
|
||||
|
||||
let args = ArgsTy::new(args_res, named, None, None);
|
||||
let args = ArgsTy::new(args_res.into_iter(), named, None, None, None);
|
||||
|
||||
Some(Ty::Args(args.into()))
|
||||
}
|
||||
|
|
@ -444,7 +444,7 @@ impl<'a, 'w> TypeChecker<'a, 'w> {
|
|||
self.weaken(rest);
|
||||
}
|
||||
|
||||
let sig = SigTy::new(pos, named, rest, Some(res_ty)).into();
|
||||
let sig = SigTy::new(pos.into_iter(), named, None, rest, Some(res_ty)).into();
|
||||
let sig = Ty::Func(sig);
|
||||
if defaults.is_empty() {
|
||||
return Some(sig);
|
||||
|
|
@ -453,7 +453,7 @@ impl<'a, 'w> TypeChecker<'a, 'w> {
|
|||
let defaults: Vec<(Interned<str>, Ty)> = defaults.into_iter().collect();
|
||||
let with_defaults = SigWithTy {
|
||||
sig: sig.into(),
|
||||
with: ArgsTy::new(vec![], defaults, None, None).into(),
|
||||
with: ArgsTy::new([].into_iter(), defaults, None, None, None).into(),
|
||||
};
|
||||
Some(Ty::With(with_defaults.into()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ impl fmt::Display for SignatureDocs {
|
|||
let mut name_prints = vec![];
|
||||
for v in self.named.values() {
|
||||
let ty = v.cano_type.as_ref().map(|t| &t.0);
|
||||
name_prints.push((v.name.clone(), ty, v.expr.clone()))
|
||||
name_prints.push((v.name.clone(), ty, v.default.clone()))
|
||||
}
|
||||
name_prints.sort();
|
||||
for (k, t, v) in name_prints {
|
||||
|
|
@ -203,11 +203,11 @@ pub struct ParamDocs {
|
|||
/// The parameter's name.
|
||||
pub name: String,
|
||||
/// Documentation for the parameter.
|
||||
pub docs: String,
|
||||
pub docs: EcoString,
|
||||
/// Inferred type of the parameter.
|
||||
pub cano_type: TypeRepr,
|
||||
/// The parameter's default name as value.
|
||||
pub expr: Option<EcoString>,
|
||||
pub default: Option<EcoString>,
|
||||
/// Is the parameter positional?
|
||||
pub positional: bool,
|
||||
/// Is the parameter named?
|
||||
|
|
@ -225,9 +225,9 @@ impl ParamDocs {
|
|||
fn new(param: &ParamSpec, ty: Option<&Ty>, doc_ty: Option<&mut ShowTypeRepr>) -> Self {
|
||||
Self {
|
||||
name: param.name.as_ref().to_owned(),
|
||||
docs: param.docs.as_ref().to_owned(),
|
||||
cano_type: format_ty(ty.or(Some(¶m.base_type)), doc_ty),
|
||||
expr: param.expr.clone(),
|
||||
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,
|
||||
|
|
@ -288,19 +288,18 @@ pub(crate) fn signature_docs(
|
|||
|
||||
let pos_in = sig
|
||||
.primary()
|
||||
.pos
|
||||
.pos()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, pos)| (pos, type_sig.as_ref().and_then(|sig| sig.pos(i))));
|
||||
let named_in = sig
|
||||
.primary()
|
||||
.named
|
||||
.named()
|
||||
.iter()
|
||||
.map(|x| (x, type_sig.as_ref().and_then(|sig| sig.named(x.0))));
|
||||
.map(|x| (x, type_sig.as_ref().and_then(|sig| sig.named(&x.name))));
|
||||
let rest_in = sig
|
||||
.primary()
|
||||
.rest
|
||||
.as_ref()
|
||||
.rest()
|
||||
.map(|x| (x, type_sig.as_ref().and_then(|sig| sig.rest_param())));
|
||||
|
||||
let ret_in = type_sig
|
||||
|
|
@ -312,9 +311,9 @@ pub(crate) fn signature_docs(
|
|||
.map(|(param, ty)| ParamDocs::new(param, ty, doc_ty.as_mut()))
|
||||
.collect();
|
||||
let named = named_in
|
||||
.map(|((name, param), ty)| {
|
||||
.map(|(param, ty)| {
|
||||
(
|
||||
name.as_ref().to_owned(),
|
||||
param.name.as_ref().to_owned(),
|
||||
ParamDocs::new(param, ty, doc_ty.as_mut()),
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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: ParamSpec { name: "angle", docs: "The angle whose sine to calculate.", base_type: (Type(angle) | Type(float) | Type(integer)), expr: None, positional: true, named: false, variadic: false, settable: false } }
|
||||
1 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "angle" }
|
||||
|
|
|
|||
|
|
@ -3,6 +3,6 @@ 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: ParamSpec { name: "red", docs: "The red component.", base_type: (Type(integer) | Type(ratio)), expr: None, positional: true, named: false, variadic: false, settable: false } }
|
||||
255 -> CallParamInfo { kind: Positional, is_content_block: false, param: ParamSpec { name: "green", docs: "The green component.", base_type: (Type(integer) | Type(ratio)), expr: None, positional: true, named: false, variadic: false, settable: false } }
|
||||
255 -> CallParamInfo { kind: Positional, is_content_block: false, param: ParamSpec { name: "blue", docs: "The blue component.", base_type: (Type(integer) | Type(ratio)), expr: None, positional: true, named: false, variadic: false, settable: false } }
|
||||
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" }
|
||||
|
|
|
|||
|
|
@ -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: ParamSpec { name: "red", docs: "The red component.", base_type: (Type(integer) | Type(ratio)), expr: None, positional: true, named: false, variadic: false, settable: false } }
|
||||
"#fff" -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "red" }
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@ source: crates/tinymist-query/src/analysis.rs
|
|||
expression: CallSnapshot(result.as_deref())
|
||||
input_file: crates/tinymist-query/src/fixtures/call_info/user.typ
|
||||
---
|
||||
1 -> CallParamInfo { kind: Positional, is_content_block: false, param: ParamSpec { name: "x", docs: "", base_type: Any, expr: None, positional: true, named: false, variadic: false, settable: false } }
|
||||
1 -> CallParamInfo { kind: Positional, is_content_block: false, param: ParamSpec { name: "y", docs: "", base_type: Any, expr: None, positional: true, named: false, variadic: false, settable: false } }
|
||||
1 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "x" }
|
||||
1 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "y" }
|
||||
|
|
|
|||
|
|
@ -3,5 +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
|
||||
---
|
||||
y: 1 -> CallParamInfo { kind: Named, is_content_block: false, param: ParamSpec { name: "y", docs: "Default value: none", base_type: Any, expr: Some("none"), positional: false, named: true, variadic: false, settable: true } }
|
||||
1 -> CallParamInfo { kind: Positional, is_content_block: false, param: ParamSpec { name: "x", docs: "", base_type: Any, expr: None, positional: true, named: false, variadic: false, settable: false } }
|
||||
y: 1 -> CallParamInfo { kind: Named, is_content_block: false, param_name: "y" }
|
||||
1 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "x" }
|
||||
|
|
|
|||
|
|
@ -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: ParamSpec { name: "x", docs: "", base_type: Any, expr: None, positional: true, named: false, variadic: false, settable: false } }
|
||||
1 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "x" }
|
||||
|
|
|
|||
|
|
@ -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: ParamSpec { name: "y", docs: "Default value: none", base_type: Any, expr: Some("none"), positional: false, named: true, variadic: false, settable: true } }
|
||||
y: 1 -> CallParamInfo { kind: Named, is_content_block: false, param_name: "y" }
|
||||
|
|
|
|||
|
|
@ -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: ParamSpec { name: "y", docs: "", base_type: Any, expr: None, positional: true, named: false, variadic: false, settable: false } }
|
||||
1 -> CallParamInfo { kind: Positional, is_content_block: false, param_name: "y" }
|
||||
|
|
|
|||
|
|
@ -215,7 +215,8 @@ fn inlay_hint(
|
|||
continue;
|
||||
};
|
||||
|
||||
if info.param.name.is_empty() {
|
||||
let name = &info.param_name;
|
||||
if name.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -257,9 +258,9 @@ fn inlay_hint(
|
|||
typst_to_lsp::offset_to_position(pos, self.encoding, self.source);
|
||||
|
||||
let label = InlayHintLabel::String(if info.kind == ParamKind::Rest {
|
||||
format!("..{}:", info.param.name)
|
||||
format!("..{name}:")
|
||||
} else {
|
||||
format!("{}:", info.param.name)
|
||||
format!("{name}:")
|
||||
});
|
||||
|
||||
self.hints.push(InlayHint {
|
||||
|
|
|
|||
|
|
@ -63,16 +63,14 @@ impl SemanticRequest for SignatureHelpRequest {
|
|||
}
|
||||
|
||||
let sig = analyze_dyn_signature(ctx, function.clone());
|
||||
let pos = &sig.primary().pos;
|
||||
let mut named = sig.primary().named.values().collect::<Vec<_>>();
|
||||
let rest = &sig.primary().rest;
|
||||
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:?}");
|
||||
|
||||
named.sort_by_key(|x| &x.name);
|
||||
|
||||
let mut active_parameter = None;
|
||||
|
||||
let mut label = def_link.name.clone();
|
||||
|
|
@ -84,10 +82,10 @@ impl SemanticRequest for SignatureHelpRequest {
|
|||
.enumerate()
|
||||
.map(|(i, pos)| (pos, type_sig.as_ref().and_then(|sig| sig.pos(i))));
|
||||
let named = named
|
||||
.into_iter()
|
||||
.iter()
|
||||
.map(|x| (x, type_sig.as_ref().and_then(|sig| sig.named(&x.name))));
|
||||
let rest = rest
|
||||
.iter()
|
||||
.into_iter()
|
||||
.map(|x| (x, type_sig.as_ref().and_then(|sig| sig.rest_param())));
|
||||
|
||||
let mut real_offset = 0;
|
||||
|
|
@ -122,7 +120,7 @@ impl SemanticRequest for SignatureHelpRequest {
|
|||
label.push_str(&format!(
|
||||
"{}: {}",
|
||||
param.name,
|
||||
ty.unwrap_or(¶m.base_type)
|
||||
ty.unwrap_or(¶m.ty)
|
||||
.describe()
|
||||
.as_deref()
|
||||
.unwrap_or("any")
|
||||
|
|
@ -130,21 +128,19 @@ impl SemanticRequest for SignatureHelpRequest {
|
|||
|
||||
params.push(LspParamInfo {
|
||||
label: lsp_types::ParameterLabel::Simple(format!("{}:", param.name)),
|
||||
documentation: if !param.docs.is_empty() {
|
||||
Some(Documentation::MarkupContent(MarkupContent {
|
||||
value: param.docs.clone().into(),
|
||||
documentation: param.docs.as_ref().map(|docs| {
|
||||
Documentation::MarkupContent(MarkupContent {
|
||||
value: docs.as_ref().into(),
|
||||
kind: MarkupKind::Markdown,
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
})
|
||||
}),
|
||||
});
|
||||
}
|
||||
label.push(')');
|
||||
let ret = type_sig
|
||||
.as_ref()
|
||||
.and_then(|sig| sig.body.as_ref())
|
||||
.or_else(|| sig.primary().ret_ty.as_ref());
|
||||
.or_else(|| sig.primary().sig_ty.body.as_ref());
|
||||
if let Some(ret_ty) = ret {
|
||||
label.push_str(" -> ");
|
||||
label.push_str(ret_ty.describe().as_deref().unwrap_or("any"));
|
||||
|
|
@ -152,7 +148,7 @@ impl SemanticRequest for SignatureHelpRequest {
|
|||
|
||||
if matches!(target, ParamTarget::Positional { .. }) {
|
||||
active_parameter =
|
||||
active_parameter.map(|x| x.min(sig.primary().pos.len().saturating_sub(1)));
|
||||
active_parameter.map(|x| x.min(sig.primary().pos_size().saturating_sub(1)));
|
||||
}
|
||||
|
||||
trace!("got signature info {label} {params:?}");
|
||||
|
|
|
|||
|
|
@ -609,7 +609,7 @@ pub static FLOW_RADIUS_DICT: Lazy<Interned<RecordTy>> = Lazy::new(|| {
|
|||
mod tests {
|
||||
use reflexo::vector::ir::DefId;
|
||||
|
||||
use super::*;
|
||||
use super::{SigTy, Ty, TypeVar};
|
||||
|
||||
// todo: map function
|
||||
// Technical Note for implementing a map function:
|
||||
|
|
@ -620,8 +620,9 @@ mod tests {
|
|||
let u = Ty::Var(TypeVar::new("u".into(), DefId(0)));
|
||||
let v = Ty::Var(TypeVar::new("v".into(), DefId(1)));
|
||||
let mapper_fn =
|
||||
Ty::Func(SigTy::new([u], Option::None, Option::None, Some(v.clone())).into());
|
||||
let map_fn = Ty::Func(SigTy::new([mapper_fn], Option::None, Option::None, Some(v)).into());
|
||||
Ty::Func(SigTy::new([u].into_iter(), None, None, None, Some(v.clone())).into());
|
||||
let map_fn =
|
||||
Ty::Func(SigTy::new([mapper_fn].into_iter(), None, None, None, Some(v)).into());
|
||||
let _ = map_fn;
|
||||
// println!("{map_fn:?}");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -612,20 +612,28 @@ impl SigTy {
|
|||
|
||||
/// Create a function type
|
||||
pub fn new(
|
||||
pos: impl IntoIterator<Item = Ty>,
|
||||
pos: impl ExactSizeIterator<Item = Ty>,
|
||||
named: impl IntoIterator<Item = (StrRef, Ty)>,
|
||||
rest: Option<Ty>,
|
||||
rest_left: Option<Ty>,
|
||||
rest_right: Option<Ty>,
|
||||
ret_ty: Option<Ty>,
|
||||
) -> Self {
|
||||
let named = named
|
||||
.into_iter()
|
||||
.map(|(name, ty)| (name, ty, Span::detached()))
|
||||
.collect::<Vec<_>>();
|
||||
let (names, types) = RecordTy::shape_fields(named);
|
||||
let spread_right = rest.is_some();
|
||||
let (names, mut named_types) = RecordTy::shape_fields(named);
|
||||
let spread_left = rest_left.is_some();
|
||||
let spread_right = rest_right.is_some();
|
||||
|
||||
let name_started = if spread_right { 1 } else { 0 } + types.len();
|
||||
let types = pos.into_iter().chain(types).chain(rest).collect::<Vec<_>>();
|
||||
let name_started = if spread_right { 1 } else { 0 } + named_types.len();
|
||||
let mut types = Vec::with_capacity(
|
||||
pos.len() + named_types.len() + spread_left as usize + spread_right as usize,
|
||||
);
|
||||
types.extend(pos);
|
||||
types.append(&mut named_types);
|
||||
types.extend(rest_left);
|
||||
types.extend(rest_right);
|
||||
|
||||
let name_started = (types.len() - name_started) as u32;
|
||||
|
||||
|
|
@ -634,7 +642,7 @@ impl SigTy {
|
|||
body: ret_ty,
|
||||
names: Interned::new(names),
|
||||
name_started,
|
||||
spread_left: false,
|
||||
spread_left,
|
||||
spread_right,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ mod tests {
|
|||
let named = named.iter().map(|(n, t)| ((*n).into(), var_ins(t)));
|
||||
let rest = rest.map(var_ins);
|
||||
let ret = ret.map(var_ins);
|
||||
SigTy::new(pos, named, rest, ret).into()
|
||||
SigTy::new(pos, named, None, rest, ret).into()
|
||||
}
|
||||
|
||||
// args*, (keys: values)*, ...rest -> ret
|
||||
|
|
|
|||
|
|
@ -597,7 +597,7 @@ pub fn param_completions<'a>(
|
|||
let mut doc = None;
|
||||
|
||||
if let Some(pos_index) = pos_index {
|
||||
let pos = primary_sig.pos.get(pos_index);
|
||||
let pos = primary_sig.get_pos(pos_index);
|
||||
log::debug!("pos_param_completion_to: {:?}", pos);
|
||||
|
||||
if let Some(pos) = pos {
|
||||
|
|
@ -605,10 +605,12 @@ pub fn param_completions<'a>(
|
|||
break 'pos_check;
|
||||
}
|
||||
|
||||
doc = Some(plain_docs_sentence(&pos.docs));
|
||||
if let Some(docs) = &pos.docs {
|
||||
doc = Some(plain_docs_sentence(docs));
|
||||
}
|
||||
|
||||
if pos.positional {
|
||||
type_completion(ctx, &pos.base_type, doc.as_deref());
|
||||
type_completion(ctx, &pos.ty, doc.as_deref());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -618,7 +620,8 @@ pub fn param_completions<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
for (name, param) in &primary_sig.named {
|
||||
for param in primary_sig.named() {
|
||||
let name = ¶m.name;
|
||||
if ctx.seen_field(name.as_ref().into()) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -632,7 +635,10 @@ pub fn param_completions<'a>(
|
|||
}
|
||||
|
||||
let _d = OnceCell::new();
|
||||
let docs = || Some(_d.get_or_init(|| plain_docs_sentence(¶m.docs)).clone());
|
||||
let docs = || {
|
||||
_d.get_or_init(|| param.docs.as_ref().map(|d| plain_docs_sentence(d.as_str())))
|
||||
.clone()
|
||||
};
|
||||
|
||||
if param.named {
|
||||
let compl = Completion {
|
||||
|
|
@ -644,7 +650,7 @@ pub fn param_completions<'a>(
|
|||
command: Some("tinymist.triggerNamedCompletion"),
|
||||
..Completion::default()
|
||||
};
|
||||
match param.base_type {
|
||||
match param.ty {
|
||||
Ty::Builtin(BuiltinTy::TextSize) => {
|
||||
for size_template in &[
|
||||
"10.5pt", "12pt", "9pt", "14pt", "8pt", "16pt", "18pt", "20pt", "22pt",
|
||||
|
|
@ -674,7 +680,7 @@ pub fn param_completions<'a>(
|
|||
}
|
||||
|
||||
if param.positional {
|
||||
type_completion(ctx, ¶m.base_type, docs().as_deref());
|
||||
type_completion(ctx, ¶m.ty, docs().as_deref());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -984,14 +990,14 @@ pub fn named_param_value_completions<'a>(
|
|||
|
||||
let primary_sig = signature.primary();
|
||||
|
||||
let Some(param) = primary_sig.named.get(name) else {
|
||||
let Some(param) = primary_sig.get_named(name) else {
|
||||
return;
|
||||
};
|
||||
if !param.named {
|
||||
return;
|
||||
}
|
||||
|
||||
let doc = Some(plain_docs_sentence(¶m.docs));
|
||||
let doc = param.docs.as_ref().map(|d| plain_docs_sentence(d.as_str()));
|
||||
|
||||
// static analysis
|
||||
if let Some(ty) = ty {
|
||||
|
|
@ -1005,13 +1011,13 @@ pub fn named_param_value_completions<'a>(
|
|||
completed = true;
|
||||
}
|
||||
|
||||
if !matches!(param.base_type, Ty::Any) {
|
||||
type_completion(ctx, ¶m.base_type, doc.as_deref());
|
||||
if !matches!(param.ty, Ty::Any) {
|
||||
type_completion(ctx, ¶m.ty, doc.as_deref());
|
||||
completed = true;
|
||||
}
|
||||
|
||||
if !completed {
|
||||
if let Some(expr) = ¶m.expr {
|
||||
if let Some(expr) = ¶m.default {
|
||||
ctx.completions.push(Completion {
|
||||
kind: CompletionKind::Constant,
|
||||
label: expr.clone(),
|
||||
|
|
|
|||
|
|
@ -605,7 +605,7 @@ function MakeDoc(root: DocElement) {
|
|||
interface DocParam {
|
||||
name: string;
|
||||
cano_type: [string, string];
|
||||
expr?: string;
|
||||
default?: string;
|
||||
}
|
||||
|
||||
function FuncItem(v: DocElement) {
|
||||
|
|
@ -761,9 +761,9 @@ function MakeDoc(root: DocElement) {
|
|||
sigTypeHighlighted(param.cano_type, paramTitle);
|
||||
}
|
||||
|
||||
if (param.expr) {
|
||||
if (param.default) {
|
||||
paramTitle.push(codeHl("op", " = "));
|
||||
paramTitle.push(code(param.expr));
|
||||
paramTitle.push(code(param.default));
|
||||
}
|
||||
|
||||
if (kind == "pos") {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue