mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-11-23 12:46:43 +00:00
feat: implement expression checker (#714)
* feat: implements expression checker * dev: resolve information * dev: delete def_use * stage * stage * stage * stage concurrent * stage concurrent * dev: better concurrency * dev: final constant evaluation improvement * dev: change reference site * dev: handle comments * dev: remove indirect import structure * dev: adjust linked_def impl * dev: finalize goto definition impl * dev: replace all old import and def_use analyses with expr analysis * dev: update expr_of snapshots * dev: split def/expr, refactor definition * dev: more consistent definition solver * dev: rename definition crate * dev: references work again * dev: resolve root decl * dev: resolve root decl * dev: resolve global definitions * dev: resolve tokens with world * feat: render semantic tokens with expression information * dev: loop detection * dev: recover type checking * dev: recover more type checking * dev: refactor analysis context * fix: process case of spread left * dev: label inference * dev: recover more signature checking * dev: recover more ident reference checking * dev: pass all tests * Revert "dev: dirty changes" This reverts commit 9ae2dacd0c96851e088feea76c61c184a1cf9722. * test: update snapshot * fix: bad cached signatures * fix: slash problem
This commit is contained in:
parent
136b162360
commit
81ebc8a635
173 changed files with 5529 additions and 4370 deletions
|
|
@ -1,11 +1,11 @@
|
|||
use std::ops::Range;
|
||||
|
||||
use log::debug;
|
||||
use typst::syntax::Span;
|
||||
|
||||
use crate::{
|
||||
analysis::{find_definition, SearchCtx},
|
||||
analysis::{Definition, SearchCtx},
|
||||
prelude::*,
|
||||
syntax::{DerefTarget, IdentRef},
|
||||
syntax::{DerefTarget, RefExpr},
|
||||
ty::Interned,
|
||||
};
|
||||
|
||||
/// The [`textDocument/references`] request is sent from the client to the
|
||||
|
|
@ -32,7 +32,7 @@ impl StatefulRequest for ReferencesRequest {
|
|||
let source = ctx.source_by_path(&self.path).ok()?;
|
||||
let deref_target = ctx.deref_syntax_at(&source, self.position, 1)?;
|
||||
|
||||
let locations = find_references(ctx, source.clone(), doc.as_ref(), deref_target)?;
|
||||
let locations = find_references(ctx, &source, doc.as_ref(), deref_target)?;
|
||||
|
||||
debug!("references: {locations:?}");
|
||||
Some(locations)
|
||||
|
|
@ -40,12 +40,12 @@ impl StatefulRequest for ReferencesRequest {
|
|||
}
|
||||
|
||||
pub(crate) fn find_references(
|
||||
ctx: &mut AnalysisContext<'_>,
|
||||
source: Source,
|
||||
document: Option<&VersionedDocument>,
|
||||
deref_target: DerefTarget<'_>,
|
||||
ctx: &mut AnalysisContext,
|
||||
source: &Source,
|
||||
doc: Option<&VersionedDocument>,
|
||||
target: DerefTarget<'_>,
|
||||
) -> Option<Vec<LspLocation>> {
|
||||
let finding_label = match deref_target {
|
||||
let finding_label = match target {
|
||||
DerefTarget::VarAccess(..) | DerefTarget::Callee(..) => false,
|
||||
DerefTarget::Label(..) | DerefTarget::Ref(..) => true,
|
||||
DerefTarget::ImportPath(..) | DerefTarget::IncludePath(..) | DerefTarget::Normal(..) => {
|
||||
|
|
@ -53,48 +53,33 @@ pub(crate) fn find_references(
|
|||
}
|
||||
};
|
||||
|
||||
let def = find_definition(ctx, source, document, deref_target)?;
|
||||
|
||||
// todo: reference of builtin items?
|
||||
let (def_fid, def_range) = def.def_at?;
|
||||
|
||||
let def_ident = IdentRef {
|
||||
name: def.name.clone(),
|
||||
range: def_range,
|
||||
};
|
||||
|
||||
let def_source = ctx.source_by_id(def_fid).ok()?;
|
||||
let root_def_use = ctx.def_use(def_source)?;
|
||||
let root_def_id = root_def_use.get_def(def_fid, &def_ident).map(|e| e.0);
|
||||
let def = ctx.definition(source, doc, target)?;
|
||||
|
||||
let worker = ReferencesWorker {
|
||||
ctx: ctx.fork_for_search(),
|
||||
references: vec![],
|
||||
def_fid,
|
||||
def_ident,
|
||||
finding_label,
|
||||
def,
|
||||
};
|
||||
|
||||
if finding_label {
|
||||
worker.label_root()
|
||||
} else {
|
||||
worker.ident_root(root_def_use, root_def_id?)
|
||||
// todo: reference of builtin items?
|
||||
worker.ident_root()
|
||||
}
|
||||
}
|
||||
|
||||
struct ReferencesWorker<'a, 'w> {
|
||||
ctx: SearchCtx<'a, 'w>,
|
||||
references: Vec<LspLocation>,
|
||||
def_fid: TypstFileId,
|
||||
def_ident: IdentRef,
|
||||
finding_label: bool,
|
||||
def: Definition,
|
||||
}
|
||||
|
||||
impl<'a, 'w> ReferencesWorker<'a, 'w> {
|
||||
fn label_root(mut self) -> Option<Vec<LspLocation>> {
|
||||
let mut ids = vec![];
|
||||
|
||||
for dep in self.ctx.ctx.resources.dependencies() {
|
||||
for dep in self.ctx.ctx.dependencies() {
|
||||
if let Ok(ref_fid) = self.ctx.ctx.file_id_by_path(&dep) {
|
||||
ids.push(ref_fid);
|
||||
}
|
||||
|
|
@ -107,22 +92,10 @@ impl<'a, 'w> ReferencesWorker<'a, 'w> {
|
|||
Some(self.references)
|
||||
}
|
||||
|
||||
fn ident_root(
|
||||
mut self,
|
||||
def_use: Arc<crate::analysis::DefUseInfo>,
|
||||
def_id: DefId,
|
||||
) -> Option<Vec<LspLocation>> {
|
||||
let def_source = self.ctx.ctx.source_by_id(self.def_fid).ok()?;
|
||||
let uri = self.ctx.ctx.uri_for_id(self.def_fid).ok()?;
|
||||
|
||||
self.push_idents(&def_source, &uri, def_use.get_refs(def_id));
|
||||
|
||||
if def_use.is_exported(def_id) {
|
||||
// Find dependents
|
||||
self.ctx.push_dependents(self.def_fid);
|
||||
while let Some(ref_fid) = self.ctx.worklist.pop() {
|
||||
self.file(ref_fid);
|
||||
}
|
||||
fn ident_root(mut self) -> Option<Vec<LspLocation>> {
|
||||
self.file(self.def.decl.file_id()?);
|
||||
while let Some(ref_fid) = self.ctx.worklist.pop() {
|
||||
self.file(ref_fid);
|
||||
}
|
||||
|
||||
Some(self.references)
|
||||
|
|
@ -131,43 +104,36 @@ impl<'a, 'w> ReferencesWorker<'a, 'w> {
|
|||
fn file(&mut self, ref_fid: TypstFileId) -> Option<()> {
|
||||
log::debug!("references: file: {ref_fid:?}");
|
||||
let ref_source = self.ctx.ctx.source_by_id(ref_fid).ok()?;
|
||||
let def_use = self.ctx.ctx.def_use(ref_source.clone())?;
|
||||
let expr_info = self.ctx.ctx.expr_stage(&ref_source);
|
||||
let uri = self.ctx.ctx.uri_for_id(ref_fid).ok()?;
|
||||
|
||||
let mut redefines = vec![];
|
||||
if let Some((id, _def)) = def_use.get_def(self.def_fid, &self.def_ident) {
|
||||
self.push_idents(&ref_source, &uri, def_use.get_refs(id));
|
||||
let t = expr_info.get_refs(self.def.decl.clone());
|
||||
self.push_idents(&ref_source, &uri, t);
|
||||
|
||||
redefines.push(id);
|
||||
|
||||
if def_use.is_exported(id) {
|
||||
self.ctx.push_dependents(ref_fid);
|
||||
}
|
||||
};
|
||||
|
||||
// All references are not resolved since static analyzers doesn't know anything
|
||||
// about labels (which is working at runtime).
|
||||
if self.finding_label {
|
||||
let label_refs = def_use.label_refs.get(&self.def_ident.name);
|
||||
self.push_ranges(&ref_source, &uri, label_refs.into_iter().flatten());
|
||||
if expr_info.is_exported(&self.def.decl) {
|
||||
self.ctx.push_dependents(ref_fid);
|
||||
}
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn push_idents<'b>(&mut self, s: &Source, u: &Url, idents: impl Iterator<Item = &'b IdentRef>) {
|
||||
self.push_ranges(s, u, idents.map(|e| &e.range));
|
||||
fn push_idents<'b>(
|
||||
&mut self,
|
||||
s: &Source,
|
||||
u: &Url,
|
||||
idents: impl Iterator<Item = (&'b Span, &'b Interned<RefExpr>)>,
|
||||
) {
|
||||
self.push_ranges(s, u, idents.map(|e| e.0));
|
||||
}
|
||||
|
||||
fn push_ranges<'b>(&mut self, s: &Source, u: &Url, rs: impl Iterator<Item = &'b Range<usize>>) {
|
||||
self.references.extend(rs.map(|rng| {
|
||||
log::debug!("references: at file: {s:?}, {rng:?}");
|
||||
|
||||
let range = self.ctx.ctx.to_lsp_range(rng.clone(), s);
|
||||
LspLocation {
|
||||
fn push_ranges<'b>(&mut self, s: &Source, u: &Url, rs: impl Iterator<Item = &'b Span>) {
|
||||
self.references.extend(rs.filter_map(|span| {
|
||||
// todo: this is not necessary a name span
|
||||
let range = self.ctx.ctx.to_lsp_range(s.range(*span)?, s);
|
||||
Some(LspLocation {
|
||||
uri: u.clone(),
|
||||
range,
|
||||
}
|
||||
})
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue