mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-04 18:58:30 +00:00
fix: dependents check
This commit is contained in:
parent
965d0c2c2d
commit
27ad6123da
6 changed files with 90 additions and 25 deletions
|
@ -37,10 +37,42 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
|
|||
Parser::parse(code).ok().map(|artifact| artifact.ast)
|
||||
}
|
||||
|
||||
pub(crate) fn check_file<S: Into<String>>(
|
||||
pub(crate) fn any_changes(&self, uri: &NormalizedUrl) -> bool {
|
||||
let deps = self.dependencies_of(uri);
|
||||
if deps.is_empty() {
|
||||
return true;
|
||||
}
|
||||
for dep in deps {
|
||||
let Some(old) = self.get_ast(&dep) else {
|
||||
return true;
|
||||
};
|
||||
if let Some(new) = self.build_ast(&dep) {
|
||||
if !ASTDiff::diff(old, &new).is_nop() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
_log!(self, "no changes: {uri}");
|
||||
false
|
||||
}
|
||||
|
||||
pub(crate) fn recheck_file(
|
||||
&mut self,
|
||||
uri: NormalizedUrl,
|
||||
code: S,
|
||||
code: impl Into<String>,
|
||||
) -> ELSResult<()> {
|
||||
if !self.any_changes(&uri) {
|
||||
_log!(self, "no changes: {uri}");
|
||||
return Ok(());
|
||||
}
|
||||
// self.clear_cache(&uri);
|
||||
self.check_file(uri, code)
|
||||
}
|
||||
|
||||
pub(crate) fn check_file(
|
||||
&mut self,
|
||||
uri: NormalizedUrl,
|
||||
code: impl Into<String>,
|
||||
) -> ELSResult<()> {
|
||||
_log!(self, "checking {uri}");
|
||||
if self.file_cache.editing.borrow().contains(&uri) {
|
||||
|
@ -53,13 +85,6 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
|
|||
} else {
|
||||
"exec"
|
||||
};
|
||||
let old = self.get_ast(&uri);
|
||||
if let Some((old, new)) = old.zip(self.build_ast(&uri)) {
|
||||
if ASTDiff::diff(old, &new).is_nop() {
|
||||
_log!(self, "no changes: {uri}");
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
let mut checker = self.get_checker(path.clone());
|
||||
let artifact = match checker.build(code.into(), mode) {
|
||||
Ok(artifact) => {
|
||||
|
|
|
@ -239,8 +239,8 @@ impl FileCache {
|
|||
}
|
||||
|
||||
pub(crate) fn update(&self, uri: &NormalizedUrl, code: String, ver: Option<i32>) {
|
||||
let ent = self.files.borrow_mut();
|
||||
let entry = ent.get(uri);
|
||||
let lock = self.files.borrow_mut();
|
||||
let entry = lock.get(uri);
|
||||
if let Some(entry) = entry {
|
||||
if ver.map_or(false, |ver| ver <= entry.ver) {
|
||||
// crate::_log!(self, "171: double update detected: {ver:?}, {}, code:\n{}", entry.ver, entry.code);
|
||||
|
@ -255,7 +255,7 @@ impl FileCache {
|
|||
1
|
||||
}
|
||||
});
|
||||
drop(ent);
|
||||
drop(lock);
|
||||
self.files.borrow_mut().insert(
|
||||
uri.clone(),
|
||||
FileCacheEntry {
|
||||
|
|
|
@ -150,12 +150,19 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
|
|||
})
|
||||
}
|
||||
|
||||
/// self is __included__
|
||||
/// self is __included__.
|
||||
/// if self is not in the graph, return empty vec
|
||||
pub fn dependencies_of(&self, uri: &NormalizedUrl) -> Vec<NormalizedUrl> {
|
||||
let graph = &self.shared.graph;
|
||||
let path = NormalizedPathBuf::from(util::uri_to_path(uri));
|
||||
graph.sort().unwrap();
|
||||
let self_node = graph.get_node(&path).unwrap();
|
||||
if let Err(err) = graph.sort() {
|
||||
// maybe key not found == self is not in the graph
|
||||
crate::_log!(self, "err: {err}");
|
||||
return vec![];
|
||||
};
|
||||
let Some(self_node) = graph.get_node(&path) else {
|
||||
return vec![];
|
||||
};
|
||||
graph
|
||||
.ref_inner()
|
||||
.iter()
|
||||
|
|
|
@ -698,8 +698,7 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
|
|||
NormalizedUrl::parse(msg["params"]["textDocument"]["uri"].as_str().unwrap())?;
|
||||
self.send_log(format!("{method}: {uri}"))?;
|
||||
let code = self.file_cache.get_entire_code(&uri)?;
|
||||
self.clear_cache(&uri);
|
||||
self.check_file(uri, code)
|
||||
self.recheck_file(uri, code)
|
||||
}
|
||||
"textDocument/didChange" => {
|
||||
let params = DidChangeTextDocumentParams::deserialize(msg["params"].clone())?;
|
||||
|
|
|
@ -2,22 +2,51 @@
|
|||
use crate::dict::Dict;
|
||||
use crate::set::Set;
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum TopoSortError {
|
||||
pub enum TopoSortErrorKind {
|
||||
CyclicReference,
|
||||
KeyNotFound,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for TopoSortError {
|
||||
impl std::fmt::Display for TopoSortErrorKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for TopoSortErrorKind {}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TopoSortError {
|
||||
pub kind: TopoSortErrorKind,
|
||||
pub msg: String,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for TopoSortError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}: {}", self.kind, self.msg)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for TopoSortError {}
|
||||
|
||||
impl TopoSortError {
|
||||
pub fn new(kind: TopoSortErrorKind, msg: String) -> Self {
|
||||
Self { kind, msg }
|
||||
}
|
||||
|
||||
pub fn key_not_found(msg: String) -> Self {
|
||||
Self::new(TopoSortErrorKind::KeyNotFound, msg)
|
||||
}
|
||||
|
||||
pub fn cycle_detected(msg: String) -> Self {
|
||||
Self::new(TopoSortErrorKind::CyclicReference, msg)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Node<T: Eq + Hash, U> {
|
||||
pub id: T,
|
||||
|
@ -65,7 +94,7 @@ fn reorder_by_key<T: Eq + Hash, U>(mut g: Graph<T, U>, idx: Vec<T>) -> Graph<T,
|
|||
g
|
||||
}
|
||||
|
||||
fn dfs<T: Eq + Hash + Clone, U>(
|
||||
fn dfs<T: Eq + Hash + Clone + Debug, U: Debug>(
|
||||
g: &Graph<T, U>,
|
||||
v: T,
|
||||
used: &mut Set<T>,
|
||||
|
@ -73,12 +102,14 @@ fn dfs<T: Eq + Hash + Clone, U>(
|
|||
) -> Result<(), TopoSortError> {
|
||||
used.insert(v.clone());
|
||||
let Some(vertex) = g.iter().find(|n| n.id == v) else {
|
||||
return Err(TopoSortError::KeyNotFound);
|
||||
return Err(TopoSortError::key_not_found(format!("{g:?}: {v:?}")));
|
||||
};
|
||||
for node_id in vertex.depends_on.iter() {
|
||||
// detecting cycles
|
||||
if used.contains(node_id) && !idx.contains(node_id) {
|
||||
return Err(TopoSortError::CyclicReference);
|
||||
return Err(TopoSortError::cycle_detected(format!(
|
||||
"{v:?} -> {node_id:?}"
|
||||
)));
|
||||
}
|
||||
if !used.contains(node_id) {
|
||||
dfs(g, node_id.clone(), used, idx)?;
|
||||
|
@ -90,7 +121,9 @@ fn dfs<T: Eq + Hash + Clone, U>(
|
|||
|
||||
/// perform topological sort on a graph
|
||||
#[allow(clippy::result_unit_err)]
|
||||
pub fn tsort<T: Eq + Hash + Clone, U>(g: Graph<T, U>) -> Result<Graph<T, U>, TopoSortError> {
|
||||
pub fn tsort<T: Eq + Hash + Clone + Debug, U: Debug>(
|
||||
g: Graph<T, U>,
|
||||
) -> Result<Graph<T, U>, TopoSortError> {
|
||||
let n = g.len();
|
||||
let mut idx = Vec::with_capacity(n);
|
||||
let mut used = Set::new();
|
||||
|
|
|
@ -66,7 +66,8 @@ impl SharedCompilerResource {
|
|||
self.warns.clear();
|
||||
}
|
||||
|
||||
/// Clear all information about the module. All child modules are also cleared.
|
||||
/// Clear all information about the module.
|
||||
/// Graph information is not cleared (due to ELS).
|
||||
pub fn clear(&self, path: &Path) {
|
||||
for child in self.graph.children(path) {
|
||||
self.clear(&child);
|
||||
|
@ -74,7 +75,7 @@ impl SharedCompilerResource {
|
|||
self.mod_cache.remove(path);
|
||||
self.py_mod_cache.remove(path);
|
||||
self.index.remove_path(path);
|
||||
self.graph.remove(path);
|
||||
// self.graph.remove(path);
|
||||
self.promises.remove(path);
|
||||
self.errors.remove(path);
|
||||
self.warns.remove(path);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue