feat: resolve definitions with dynamic analysis (#1904)
Some checks failed
tinymist::ci / Duplicate Actions Detection (push) Has been cancelled
tinymist::ci / Check Clippy, Formatting, Completion, Documentation, and Tests (Linux) (push) Has been cancelled
tinymist::ci / Check Minimum Rust version and Tests (Windows) (push) Has been cancelled
tinymist::ci / prepare-build (push) Has been cancelled
tinymist::gh_pages / build-gh-pages (push) Has been cancelled
tinymist::ci / build-vsc-assets (push) Has been cancelled
tinymist::ci / build-vscode (push) Has been cancelled
tinymist::ci / build-vscode-others (push) Has been cancelled
tinymist::ci / publish-vscode (push) Has been cancelled
tinymist::ci / E2E Tests (darwin-arm64 on macos-latest) (push) Has been cancelled
tinymist::ci / E2E Tests (linux-x64 on ubuntu-22.04) (push) Has been cancelled
tinymist::ci / E2E Tests (linux-x64 on ubuntu-latest) (push) Has been cancelled
tinymist::ci / E2E Tests (win32-x64 on windows-2022) (push) Has been cancelled
tinymist::ci / E2E Tests (win32-x64 on windows-latest) (push) Has been cancelled
tinymist::ci / build-binary (push) Has been cancelled

* feat: dyn resolve targets

* fix: test cases

* feat: static analysis again based on dyn analysis result
This commit is contained in:
Myriad-Dreamin 2025-07-15 01:15:33 +08:00 committed by GitHub
parent 35e8f447b0
commit 1359e9975b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 218 additions and 69 deletions

View file

@ -10,6 +10,7 @@ use parking_lot::Mutex;
use rustc_hash::FxHashMap;
use tinymist_analysis::docs::DocString;
use tinymist_analysis::stats::AllocStats;
use tinymist_analysis::syntax::classify_def_loosely;
use tinymist_analysis::ty::term_value;
use tinymist_analysis::{analyze_expr_, analyze_import_};
use tinymist_lint::LintInfo;
@ -861,12 +862,68 @@ impl SharedContext {
definition(self, source, doc, syntax)
}
pub(crate) fn type_of_span(self: &Arc<Self>, span: Span) -> Option<Ty> {
self.type_of_span_(&self.source_by_id(span.id()?).ok()?, span)
pub(crate) fn def_of_syntax_or_dyn(
self: &Arc<Self>,
source: &Source,
doc: Option<&TypstDocument>,
syntax: SyntaxClass,
) -> Option<Definition> {
let def = self.def_of_syntax(source, doc, syntax.clone());
match def.as_ref().map(|d| d.decl.kind()) {
// todo: DefKind::Function
Some(DefKind::Reference | DefKind::Module | DefKind::Function) => return def,
Some(DefKind::Struct | DefKind::Constant | DefKind::Variable) | None => {}
}
// Checks that we resolved a high-equality definition.
let know_ty_well = def
.as_ref()
.and_then(|d| self.simplified_type_of_span(d.decl.span()))
.filter(|ty| !matches!(ty, Ty::Any))
.is_some();
if know_ty_well {
return def;
}
let def_ref = def.as_ref();
let def_name = || Some(def_ref?.name().clone());
let dyn_def = self
.analyze_expr(syntax.node())
.iter()
.find_map(|(value, _)| {
let def = Definition::from_value(value.clone(), def_name)?;
None.or_else(|| {
let source = self.source_by_id(def.decl.file_id()?).ok()?;
let node = LinkedNode::new(source.root()).find(def.decl.span())?;
let def_at_the_span = classify_def_loosely(node)?;
self.def_of_span(&source, doc, def_at_the_span.name()?.span())
})
.or(Some(def))
});
// Uses the dynamic definition or the fallback definition.
dyn_def.or(def)
}
pub(crate) fn type_of_span_(self: &Arc<Self>, source: &Source, span: Span) -> Option<Ty> {
self.type_check(source).type_of_span(span)
pub(crate) fn simplified_type_of_span(self: &Arc<Self>, span: Span) -> Option<Ty> {
let source = self.source_by_id(span.id()?).ok()?;
let (ti, ty) = self.type_of_span_(&source, span)?;
Some(ti.simplify(ty, false))
}
pub(crate) fn type_of_span(self: &Arc<Self>, span: Span) -> Option<Ty> {
let source = self.source_by_id(span.id()?).ok()?;
Some(self.type_of_span_(&source, span)?.1)
}
pub(crate) fn type_of_span_(
self: &Arc<Self>,
source: &Source,
span: Span,
) -> Option<(Arc<TypeInfo>, Ty)> {
let ti = self.type_check(source);
let ty = ti.type_of_span(span)?;
Some((ti, ty))
}
pub(crate) fn post_type_of_node(self: &Arc<Self>, node: LinkedNode) -> Option<Ty> {
@ -889,6 +946,24 @@ impl SharedContext {
super::sig_of_type(self, ti, ty)
}
pub(crate) fn sig_of_type_or_dyn(
self: &Arc<Self>,
ti: &TypeInfo,
callee_ty: Ty,
callee: &SyntaxNode,
) -> Option<Signature> {
self.sig_of_type(ti, callee_ty).or_else(|| {
self.analyze_expr(callee).iter().find_map(|(value, _)| {
let Value::Func(callee) = value else {
return None;
};
// Converts with cache
analyze_signature(self, SignatureTarget::Runtime(callee.clone()))
})
})
}
/// Try to find imported target from the current source file.
/// This function will try to resolves target statically.
///