Skip to content

Commit b0959b1

Browse files
committed
fix(els): file data inconsistencies
1 parent ca83d09 commit b0959b1

File tree

4 files changed

+66
-28
lines changed

4 files changed

+66
-28
lines changed

crates/els/file_cache.rs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub fn _get_code_from_uri(uri: &Url) -> ELSResult<String> {
2828
#[derive(Debug, Clone)]
2929
pub struct FileCacheEntry {
3030
pub code: String,
31+
pub ver: i32,
3132
pub metadata: Metadata,
3233
pub token_stream: Option<TokenStream>,
3334
}
@@ -102,25 +103,11 @@ impl FileCache {
102103
pub fn get(&self, uri: &NormalizedUrl) -> ELSResult<&FileCacheEntry> {
103104
let Some(entry) = unsafe { self.files.as_ref() }.get(uri) else {
104105
let code = _get_code_from_uri(uri)?;
105-
self.update(uri, code);
106+
self.update(uri, code, None);
106107
let entry = unsafe { self.files.as_ref() }.get(uri).ok_or("not found")?;
107108
return Ok(entry);
108109
};
109-
let last_modified = entry.metadata.modified().unwrap();
110-
let current_modified = metadata(uri.to_file_path().unwrap())
111-
.unwrap()
112-
.modified()
113-
.unwrap();
114-
if last_modified != current_modified {
115-
let code = _get_code_from_uri(uri)?;
116-
self.update(uri, code);
117-
unsafe { self.files.as_ref() }
118-
.get(uri)
119-
.ok_or("not found".into())
120-
} else {
121-
let entry = unsafe { self.files.as_ref() }.get(uri).ok_or("not found")?;
122-
Ok(entry)
123-
}
110+
Ok(entry)
124111
}
125112

126113
pub fn get_token_stream(&self, uri: &NormalizedUrl) -> Option<&TokenStream> {
@@ -163,13 +150,28 @@ impl FileCache {
163150
}
164151
}
165152

166-
pub(crate) fn update(&self, uri: &NormalizedUrl, code: String) {
153+
pub(crate) fn update(&self, uri: &NormalizedUrl, code: String, ver: Option<i32>) {
154+
let entry = unsafe { self.files.as_ref() }.get(uri);
155+
if let Some(entry) = entry {
156+
if ver.map_or(false, |ver| ver <= entry.ver) {
157+
// crate::_log!("171: double update detected: {ver:?}, {}, code:\n{}", entry.ver, entry.code);
158+
return;
159+
}
160+
}
167161
let metadata = metadata(uri.to_file_path().unwrap()).unwrap();
168162
let token_stream = Lexer::from_str(code.clone()).lex().ok();
163+
let ver = ver.unwrap_or({
164+
if let Some(entry) = entry {
165+
entry.ver
166+
} else {
167+
1
168+
}
169+
});
169170
self.files.borrow_mut().insert(
170171
uri.clone(),
171172
FileCacheEntry {
172173
code,
174+
ver,
173175
metadata,
174176
token_stream,
175177
},
@@ -187,6 +189,7 @@ impl FileCache {
187189
code.replace_range(start..end, new_code);
188190
let token_stream = Lexer::from_str(code.clone()).lex().ok();
189191
entry.code = code;
192+
// entry.ver += 1;
190193
entry.metadata = metadata;
191194
entry.token_stream = token_stream;
192195
}
@@ -196,6 +199,10 @@ impl FileCache {
196199
let Some(entry) = unsafe { self.files.as_mut() }.get_mut(&uri) else {
197200
return;
198201
};
202+
if entry.ver >= params.text_document.version {
203+
// crate::_log!("212: double update detected {}, {}, code:\n{}", entry.ver, params.text_document.version, entry.code);
204+
return;
205+
}
199206
let metadata = metadata(uri.to_file_path().unwrap()).unwrap();
200207
let mut code = entry.code.clone();
201208
for change in params.content_changes {
@@ -206,6 +213,7 @@ impl FileCache {
206213
}
207214
let token_stream = Lexer::from_str(code.clone()).lex().ok();
208215
entry.code = code;
216+
entry.ver = params.text_document.version;
209217
entry.metadata = metadata;
210218
entry.token_stream = token_stream;
211219
}

crates/els/server.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ use erg_compiler::ty::HasType;
2323

2424
use lsp_types::{
2525
ClientCapabilities, CodeActionKind, CodeActionOptions, CodeActionProviderCapability,
26-
CodeLensOptions, CompletionOptions, DidChangeTextDocumentParams, ExecuteCommandOptions,
27-
HoverProviderCapability, InitializeResult, OneOf, Position, SemanticTokenType,
28-
SemanticTokensFullOptions, SemanticTokensLegend, SemanticTokensOptions,
26+
CodeLensOptions, CompletionOptions, DidChangeTextDocumentParams, DidOpenTextDocumentParams,
27+
ExecuteCommandOptions, HoverProviderCapability, InitializeResult, OneOf, Position,
28+
SemanticTokenType, SemanticTokensFullOptions, SemanticTokensLegend, SemanticTokensOptions,
2929
SemanticTokensServerCapabilities, ServerCapabilities, SignatureHelpOptions,
3030
WorkDoneProgressOptions,
3131
};
@@ -104,9 +104,10 @@ impl From<&str> for OptionalFeatures {
104104
}
105105
}
106106

107+
#[macro_export]
107108
macro_rules! _log {
108109
($($arg:tt)*) => {
109-
send_log(format!($($arg)*)).unwrap();
110+
$crate::server::send_log(format!($($arg)*)).unwrap();
110111
};
111112
}
112113

@@ -453,11 +454,12 @@ impl<Checker: BuildRunnable> Server<Checker> {
453454
"initialized" => send_log("successfully bound"),
454455
"exit" => self.exit(),
455456
"textDocument/didOpen" => {
456-
let uri =
457-
NormalizedUrl::parse(msg["params"]["textDocument"]["uri"].as_str().unwrap())?;
457+
let params = DidOpenTextDocumentParams::deserialize(msg["params"].clone())?;
458+
let uri = NormalizedUrl::new(params.text_document.uri);
458459
send_log(format!("{method}: {uri}"))?;
459-
let code = msg["params"]["textDocument"]["text"].as_str().unwrap();
460-
self.file_cache.update(&uri, code.to_string());
460+
let code = params.text_document.text;
461+
let ver = params.text_document.version;
462+
self.file_cache.update(&uri, code.clone(), Some(ver));
461463
self.check_file(uri, code)
462464
}
463465
"textDocument/didSave" => {
@@ -471,7 +473,6 @@ impl<Checker: BuildRunnable> Server<Checker> {
471473
"textDocument/didChange" => {
472474
let params = DidChangeTextDocumentParams::deserialize(msg["params"].clone())?;
473475
self.file_cache.incremental_update(params.clone());
474-
send_log("file cache updated")?;
475476
if self.opt_features.contains(&OptionalFeatures::CheckOnType) {
476477
let uri = NormalizedUrl::new(params.text_document.uri);
477478
self.quick_check_file(uri)?;
@@ -580,7 +581,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
580581
let path = util::uri_to_path(uri);
581582
shared.mod_cache.remove(&path);
582583
shared.index.remove_path(&path);
583-
shared.graph.initialize();
584+
shared.graph.remove(&path);
584585
}
585586
}
586587
}

crates/erg_common/tsort.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ impl std::error::Error for TopoSortError {}
2222
pub struct Node<T: Eq + Hash, U> {
2323
pub id: T,
2424
pub data: U,
25-
depends_on: Set<T>,
25+
pub depends_on: Set<T>,
2626
}
2727

2828
impl<T: Eq + Hash, U> Node<T, U> {

crates/erg_compiler/module/graph.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::fmt;
12
use std::path::{Path, PathBuf};
23

34
use erg_common::shared::Shared;
@@ -7,6 +8,19 @@ use erg_common::{normalize_path, set};
78
#[derive(Debug, Clone, Default)]
89
pub struct ModuleGraph(Graph<PathBuf, ()>);
910

11+
impl fmt::Display for ModuleGraph {
12+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13+
for node in self.0.iter() {
14+
writeln!(f, "{} depends on {{", node.id.display())?;
15+
for dep in node.depends_on.iter() {
16+
writeln!(f, "{}, ", dep.display())?;
17+
}
18+
writeln!(f, "}}, ")?;
19+
}
20+
Ok(())
21+
}
22+
}
23+
1024
impl IntoIterator for ModuleGraph {
1125
type Item = Node<PathBuf, ()>;
1226
type IntoIter = std::vec::IntoIter<Self::Item>;
@@ -62,6 +76,11 @@ impl ModuleGraph {
6276
Ok(())
6377
}
6478

79+
pub fn remove(&mut self, path: &Path) {
80+
let path = normalize_path(path.to_path_buf());
81+
self.0.retain(|n| n.id != path);
82+
}
83+
6584
pub fn initialize(&mut self) {
6685
self.0.clear();
6786
}
@@ -70,6 +89,12 @@ impl ModuleGraph {
7089
#[derive(Debug, Clone, Default)]
7190
pub struct SharedModuleGraph(Shared<ModuleGraph>);
7291

92+
impl fmt::Display for SharedModuleGraph {
93+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94+
write!(f, "{}", self.0.borrow())
95+
}
96+
}
97+
7398
impl IntoIterator for SharedModuleGraph {
7499
type Item = Node<PathBuf, ()>;
75100
type IntoIter = std::vec::IntoIter<Self::Item>;
@@ -104,6 +129,10 @@ impl SharedModuleGraph {
104129
ref_graph.iter()
105130
}
106131

132+
pub fn remove(&self, path: &Path) {
133+
self.0.borrow_mut().remove(path);
134+
}
135+
107136
#[allow(clippy::result_unit_err)]
108137
pub fn sort(&self) -> Result<(), TopoSortError> {
109138
self.0.borrow_mut().sort()

0 commit comments

Comments
 (0)