mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-12-23 08:47:50 +00:00
cache
This commit is contained in:
parent
e4a9096075
commit
06da3f8f25
3 changed files with 94 additions and 8 deletions
|
|
@ -6,6 +6,18 @@ use typst::syntax::{Span, ast};
|
|||
|
||||
use crate::DiagnosticVec;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DiscardByReturnAnalysis {
|
||||
cfg: Cfg,
|
||||
reachable: Vec<bool>,
|
||||
states: Vec<MustReturnState>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct DiscardByReturnCache {
|
||||
by_span: std::collections::HashMap<u64, std::sync::Arc<DiscardByReturnAnalysis>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum MustReturnKind {
|
||||
No,
|
||||
|
|
@ -466,15 +478,27 @@ fn warn_meta(expr: ast::Expr<'_>) -> Option<WarnMeta> {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn lint_discarded_by_function_return(diag: &mut DiagnosticVec, body: ast::Expr<'_>) {
|
||||
fn analyze_discarded_by_function_return(body: ast::Expr<'_>) -> Option<DiscardByReturnAnalysis> {
|
||||
let cfg = Builder::new(body.span()).build_body(body);
|
||||
if !cfg.has_return {
|
||||
return;
|
||||
return None;
|
||||
}
|
||||
|
||||
let reachable = cfg.reachable_from_entry();
|
||||
let states = cfg.compute_states();
|
||||
|
||||
Some(DiscardByReturnAnalysis {
|
||||
cfg,
|
||||
reachable,
|
||||
states,
|
||||
})
|
||||
}
|
||||
|
||||
fn emit_discarded_by_function_return(diag: &mut DiagnosticVec, analysis: &DiscardByReturnAnalysis) {
|
||||
let cfg = &analysis.cfg;
|
||||
let reachable = &analysis.reachable;
|
||||
let states = &analysis.states;
|
||||
|
||||
for (id, node) in cfg.nodes.iter().enumerate() {
|
||||
if !reachable[id] {
|
||||
continue;
|
||||
|
|
@ -520,3 +544,22 @@ pub(crate) fn lint_discarded_by_function_return(diag: &mut DiagnosticVec, body:
|
|||
diag.push(diag_);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn lint_discarded_by_function_return_cached(
|
||||
cache: &mut DiscardByReturnCache,
|
||||
diag: &mut DiagnosticVec,
|
||||
body: ast::Expr<'_>,
|
||||
) {
|
||||
let key = body.span().into_raw().get();
|
||||
if let Some(analysis) = cache.by_span.get(&key) {
|
||||
emit_discarded_by_function_return(diag, analysis);
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(analysis) = analyze_discarded_by_function_return(body) else {
|
||||
return;
|
||||
};
|
||||
let analysis = std::sync::Arc::new(analysis);
|
||||
emit_discarded_by_function_return(diag, &analysis);
|
||||
cache.by_span.insert(key, analysis);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,13 @@ mod cfg;
|
|||
/// A type alias for a vector of diagnostics.
|
||||
type DiagnosticVec = EcoVec<SourceDiagnostic>;
|
||||
|
||||
#[derive(Default)]
|
||||
/// Cache container for lint analyses that are expensive to recompute (e.g. CFG +
|
||||
/// dataflow for particular bodies).
|
||||
pub struct LintCaches {
|
||||
discard_by_return: cfg::DiscardByReturnCache,
|
||||
}
|
||||
|
||||
/// The lint information about a file.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LintInfo {
|
||||
|
|
@ -39,8 +46,10 @@ pub fn lint_file(
|
|||
ei: &ExprInfo,
|
||||
ti: Arc<TypeInfo>,
|
||||
known_issues: KnownIssues,
|
||||
caches: &mut LintCaches,
|
||||
) -> LintInfo {
|
||||
let diagnostics = Linter::new(world, ei.clone(), ti, known_issues).lint(ei.source.root());
|
||||
let diagnostics =
|
||||
Linter::new(world, ei.clone(), ti, known_issues, caches).lint(ei.source.root());
|
||||
LintInfo {
|
||||
revision: ei.revision,
|
||||
fid: ei.fid,
|
||||
|
|
@ -77,7 +86,7 @@ impl KnownIssues {
|
|||
}
|
||||
}
|
||||
|
||||
struct Linter<'w> {
|
||||
struct Linter<'w, 'c> {
|
||||
world: &'w LspWorld,
|
||||
ei: ExprInfo,
|
||||
ti: Arc<TypeInfo>,
|
||||
|
|
@ -85,14 +94,16 @@ struct Linter<'w> {
|
|||
diag: DiagnosticVec,
|
||||
loop_info: Option<LoopInfo>,
|
||||
func_info: Option<FuncInfo>,
|
||||
caches: &'c mut LintCaches,
|
||||
}
|
||||
|
||||
impl<'w> Linter<'w> {
|
||||
impl<'w, 'c> Linter<'w, 'c> {
|
||||
fn new(
|
||||
world: &'w LspWorld,
|
||||
ei: ExprInfo,
|
||||
ti: Arc<TypeInfo>,
|
||||
known_issues: KnownIssues,
|
||||
caches: &'c mut LintCaches,
|
||||
) -> Self {
|
||||
Self {
|
||||
world,
|
||||
|
|
@ -102,6 +113,7 @@ impl<'w> Linter<'w> {
|
|||
diag: EcoVec::new(),
|
||||
loop_info: None,
|
||||
func_info: None,
|
||||
caches,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -428,7 +440,11 @@ impl<'w> Linter<'w> {
|
|||
|
||||
let body = expr.body();
|
||||
this.expr(body);
|
||||
cfg::lint_discarded_by_function_return(&mut this.diag, body);
|
||||
cfg::lint_discarded_by_function_return_cached(
|
||||
&mut this.caches.discard_by_return,
|
||||
&mut this.diag,
|
||||
body,
|
||||
);
|
||||
|
||||
Some(())
|
||||
})
|
||||
|
|
@ -441,7 +457,11 @@ impl<'w> Linter<'w> {
|
|||
|
||||
let body = expr.body();
|
||||
this.expr(body);
|
||||
cfg::lint_discarded_by_function_return(&mut this.diag, body);
|
||||
cfg::lint_discarded_by_function_return_cached(
|
||||
&mut this.caches.discard_by_return,
|
||||
&mut this.diag,
|
||||
body,
|
||||
);
|
||||
|
||||
Some(())
|
||||
})
|
||||
|
|
|
|||
|
|
@ -836,9 +836,25 @@ impl SharedContext {
|
|||
let ei = self.expr_stage(source);
|
||||
let ti = self.type_check(source);
|
||||
let guard = self.query_stat(source.id(), "lint");
|
||||
|
||||
let source_hash = hash128(source);
|
||||
let lint_caches = self.slot.lint_caches.compute(source.id(), |prev| {
|
||||
if let Some(prev) = prev {
|
||||
if prev.lock().source_hash == source_hash {
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
|
||||
Arc::new(Mutex::new(LintCachesSlot {
|
||||
source_hash,
|
||||
caches: tinymist_lint::LintCaches::default(),
|
||||
}))
|
||||
});
|
||||
|
||||
self.slot.lint.compute(hash128(&(&ei, &ti, issues)), |_| {
|
||||
guard.miss();
|
||||
tinymist_lint::lint_file(self.world(), &ei, ti, issues.clone())
|
||||
let mut caches = lint_caches.lock();
|
||||
tinymist_lint::lint_file(self.world(), &ei, ti, issues.clone(), &mut caches.caches)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1325,6 +1341,11 @@ pub struct ModuleAnalysisLocalCache {
|
|||
type_check: OnceLock<Arc<TypeInfo>>,
|
||||
}
|
||||
|
||||
struct LintCachesSlot {
|
||||
source_hash: u128,
|
||||
caches: tinymist_lint::LintCaches,
|
||||
}
|
||||
|
||||
/// A revision-managed (per input change) cache for all level of analysis
|
||||
/// results of a module.
|
||||
#[derive(Default)]
|
||||
|
|
@ -1391,6 +1412,7 @@ impl AnalysisRevCache {
|
|||
expr_stage: slot.data.expr_stage.crawl(revision.get()),
|
||||
type_check: slot.data.type_check.crawl(revision.get()),
|
||||
lint: slot.data.lint.crawl(revision.get()),
|
||||
lint_caches: slot.data.lint_caches.crawl(revision.get()),
|
||||
})
|
||||
.unwrap_or_else(|| self.default_slot.clone())
|
||||
})
|
||||
|
|
@ -1424,6 +1446,7 @@ struct AnalysisRevSlot {
|
|||
expr_stage: IncrCacheMap<u128, ExprInfo>,
|
||||
type_check: IncrCacheMap<u128, Arc<TypeInfo>>,
|
||||
lint: IncrCacheMap<u128, LintInfo>,
|
||||
lint_caches: IncrCacheMap<TypstFileId, Arc<Mutex<LintCachesSlot>>>,
|
||||
}
|
||||
|
||||
impl Drop for AnalysisRevSlot {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue