fix: bugs

This commit is contained in:
Shunsuke Shibayama 2023-05-13 16:14:34 +09:00
parent 33e1b776cb
commit ced04e5d6a
8 changed files with 71 additions and 65 deletions

View file

@ -28,11 +28,12 @@ impl<Checker: BuildRunnable> Server<Checker> {
send_log("visitor not found")?; send_log("visitor not found")?;
return Ok(None); return Ok(None);
}; };
let Some(artifact) = self.artifacts.get(&uri) else { let Some(result) = self.artifacts.get(&uri) else {
send_log("artifact not found")?; send_log("artifact not found")?;
return Ok(None); return Ok(None);
}; };
let warns = artifact let warns = result
.artifact
.warns .warns
.iter() .iter()
.filter(|warn| warn.core.main_message.ends_with("is not used")) .filter(|warn| warn.core.main_message.ends_with("is not used"))

View file

@ -24,8 +24,8 @@ impl<Checker: BuildRunnable> Server<Checker> {
fn send_trait_impls_lens(&mut self, uri: &NormalizedUrl) -> ELSResult<Vec<CodeLens>> { fn send_trait_impls_lens(&mut self, uri: &NormalizedUrl) -> ELSResult<Vec<CodeLens>> {
let mut result = vec![]; let mut result = vec![];
if let Some(artifact) = self.artifacts.get(uri) { if let Some(analysis) = self.artifacts.get(uri) {
if let Some(hir) = &artifact.object { if let Some(hir) = &analysis.artifact.object {
for chunk in hir.module.iter() { for chunk in hir.module.iter() {
match chunk { match chunk {
Expr::Def(def) if def.def_kind().is_trait() => { Expr::Def(def) if def.def_kind().is_trait() => {

View file

@ -4,12 +4,12 @@ use erg_common::style::*;
use erg_common::traits::Stream; use erg_common::traits::Stream;
use erg_compiler::artifact::BuildRunnable; use erg_compiler::artifact::BuildRunnable;
use erg_compiler::erg_parser::Parser;
use erg_compiler::error::CompileErrors; use erg_compiler::error::CompileErrors;
use lsp_types::{Diagnostic, DiagnosticSeverity, Position, PublishDiagnosticsParams, Range, Url}; use lsp_types::{Diagnostic, DiagnosticSeverity, Position, PublishDiagnosticsParams, Range, Url};
use crate::server::{send, send_log, DefaultFeatures, ELSResult, Server}; use crate::diff::{ASTDiff, HIRDiff};
use crate::server::{send, send_log, AnalysisResult, DefaultFeatures, ELSResult, Server};
use crate::util::{self, NormalizedUrl}; use crate::util::{self, NormalizedUrl};
impl<Checker: BuildRunnable> Server<Checker> { impl<Checker: BuildRunnable> Server<Checker> {
@ -36,7 +36,10 @@ impl<Checker: BuildRunnable> Server<Checker> {
send_log(format!("{uri}, warns: {}", diags.len()))?; send_log(format!("{uri}, warns: {}", diags.len()))?;
self.send_diagnostics(uri, diags)?; self.send_diagnostics(uri, diags)?;
} }
self.artifacts.insert(uri.clone(), artifact.into()); if let Some(module) = self.file_cache.get_ast(&uri) {
self.artifacts
.insert(uri.clone(), AnalysisResult::new(module, artifact.into()));
}
} }
Err(artifact) => { Err(artifact) => {
send_log(format!("found errors: {}", artifact.errors.len()))?; send_log(format!("found errors: {}", artifact.errors.len()))?;
@ -55,7 +58,10 @@ impl<Checker: BuildRunnable> Server<Checker> {
send_log(format!("{uri}, errs & warns: {}", diags.len()))?; send_log(format!("{uri}, errs & warns: {}", diags.len()))?;
self.send_diagnostics(uri, diags)?; self.send_diagnostics(uri, diags)?;
} }
self.artifacts.insert(uri.clone(), artifact); if let Some(module) = self.file_cache.get_ast(&uri) {
self.artifacts
.insert(uri.clone(), AnalysisResult::new(module, artifact));
}
} }
} }
if let Some(module) = checker.pop_context() { if let Some(module) = checker.pop_context() {
@ -72,38 +78,26 @@ impl<Checker: BuildRunnable> Server<Checker> {
} }
pub(crate) fn quick_check_file(&mut self, uri: NormalizedUrl) -> ELSResult<()> { pub(crate) fn quick_check_file(&mut self, uri: NormalizedUrl) -> ELSResult<()> {
// send_log(format!("checking {uri}"))?; let Some(old) = self.artifacts.get(&uri).map(|r| &r.ast) else {
let Some(ts) = self.file_cache.get_token_stream(&uri) else { crate::_log!("not found");
return Ok(()); return Ok(());
}; };
let mut parser = Parser::new(ts); let Some(new) = self.file_cache.get_ast(&uri) else {
let Ok(module) = parser.parse() else { crate::_log!("not found");
return Ok(()); return Ok(());
}; };
let path = util::uri_to_path(&uri); let ast_diff = ASTDiff::diff(old, &new);
let code = self.file_cache.get_entire_code(&uri)?; crate::_log!("diff: {ast_diff:?}");
let mode = if path.to_string_lossy().ends_with(".d.er") { if let Some(mut lowerer) = self.get_lowerer(&uri) {
"declare" let hir = self
} else { .artifacts
"exec" .get_mut(&uri)
}; .and_then(|r| r.artifact.object.as_mut());
if let Some(mut lowerer) = self.get_lowerer(&path) {} if let Some((hir_diff, hir)) = HIRDiff::new(ast_diff, &mut lowerer).zip(hir) {
let mut checker = self.get_checker(path); crate::_log!("hir_diff: {hir_diff:?}");
match checker.build(code, mode) { hir_diff.update(hir);
Ok(artifact) => {
self.artifacts.insert(uri.clone(), artifact.into());
} }
Err(artifact) => { self.restore_mod_ctx(&uri, lowerer.pop_mod_ctx().unwrap());
self.artifacts.insert(uri.clone(), artifact);
}
}
if let Some(module) = checker.pop_context() {
self.modules.insert(uri.clone(), module);
}
let dependents = self.dependents_of(&uri);
for dep in dependents {
// _log!("dep: {dep}");
self.quick_check_file(dep)?;
} }
Ok(()) Ok(())
} }

View file

@ -2,7 +2,7 @@ use std::cmp::Ordering::*;
use erg_common::traits::Stream; use erg_common::traits::Stream;
use erg_compiler::erg_parser::ast; use erg_compiler::erg_parser::ast;
use erg_compiler::erg_parser::ast::AST; use erg_compiler::erg_parser::ast::Module;
use erg_compiler::hir; use erg_compiler::hir;
use erg_compiler::hir::HIR; use erg_compiler::hir::HIR;
use erg_compiler::lower::ASTLowerer; use erg_compiler::lower::ASTLowerer;
@ -23,30 +23,27 @@ pub enum ASTDiff {
/// diff(old: {x, y, z}, new: {x, a, z}) => ASTDiff::Modification(1) /// diff(old: {x, y, z}, new: {x, a, z}) => ASTDiff::Modification(1)
/// diff(old: {x, y, z}, new: {x, y, z}) => ASTDiff::Nop /// diff(old: {x, y, z}, new: {x, y, z}) => ASTDiff::Nop
impl ASTDiff { impl ASTDiff {
pub fn diff(old: AST, new: AST) -> ASTDiff { pub fn diff(old: &Module, new: &Module) -> ASTDiff {
match old.module.len().cmp(&new.module.len()) { match old.len().cmp(&new.len()) {
Less => { Less => {
let idx = new let idx = new
.module
.iter() .iter()
.zip(old.module.iter()) .zip(old.iter())
.position(|(new, old)| new != old) .position(|(new, old)| new != old)
.unwrap(); .unwrap_or(new.len() - 1);
Self::Addition(idx, new.module.get(idx).unwrap().clone()) Self::Addition(idx, new.get(idx).unwrap().clone())
} }
Greater => Self::Deletion( Greater => Self::Deletion(
old.module old.iter()
.iter() .zip(new.iter())
.zip(new.module.iter())
.position(|(old, new)| old != new) .position(|(old, new)| old != new)
.unwrap(), .unwrap_or(old.len() - 1),
), ),
Equal => old Equal => old
.module
.iter() .iter()
.zip(new.module.iter()) .zip(new.iter())
.position(|(old, new)| old != new) .position(|(old, new)| old != new)
.map(|idx| Self::Modification(idx, new.module.get(idx).unwrap().clone())) .map(|idx| Self::Modification(idx, new.get(idx).unwrap().clone()))
.unwrap_or(Self::Nop), .unwrap_or(Self::Nop),
} }
} }

View file

@ -1,6 +1,8 @@
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
use erg_compiler::erg_parser::ast::Module;
use erg_compiler::erg_parser::Parser;
use lsp_types::{ use lsp_types::{
DidChangeTextDocumentParams, FileOperationFilter, FileOperationPattern, DidChangeTextDocumentParams, FileOperationFilter, FileOperationPattern,
FileOperationPatternKind, FileOperationRegistrationOptions, OneOf, Position, Range, FileOperationPatternKind, FileOperationRegistrationOptions, OneOf, Position, Range,
@ -126,6 +128,12 @@ impl FileCache {
self.files.borrow_mut().get(uri)?.token_stream.clone() self.files.borrow_mut().get(uri)?.token_stream.clone()
} }
pub fn get_ast(&self, uri: &NormalizedUrl) -> Option<Module> {
let ts = self.get_token_stream(uri)?;
let mut parser = Parser::new(ts);
parser.parse().ok()
}
pub fn get_token(&self, uri: &NormalizedUrl, pos: Position) -> Option<Token> { pub fn get_token(&self, uri: &NormalizedUrl, pos: Position) -> Option<Token> {
let _ = self.load_once(uri); let _ = self.load_once(uri);
let ent = self.files.borrow_mut(); let ent = self.files.borrow_mut();

View file

@ -95,7 +95,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
let mut result = vec![]; let mut result = vec![];
if let Some(IncompleteArtifact { if let Some(IncompleteArtifact {
object: Some(hir), .. object: Some(hir), ..
}) = self.artifacts.get(&uri) }) = self.artifacts.get(&uri).map(|r| &r.artifact)
{ {
for chunk in hir.module.iter() { for chunk in hir.module.iter() {
result.extend(self.get_expr_hint(chunk)); result.extend(self.get_expr_hint(chunk));

View file

@ -209,7 +209,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
let mut imports = vec![]; let mut imports = vec![];
if let Some(IncompleteArtifact { if let Some(IncompleteArtifact {
object: Some(hir), .. object: Some(hir), ..
}) = self.artifacts.get(target) }) = self.artifacts.get(target).map(|r| &r.artifact)
{ {
for chunk in hir.module.iter() { for chunk in hir.module.iter() {
imports.extend(Self::extract_import_symbols(chunk, needle_module_name)); imports.extend(Self::extract_import_symbols(chunk, needle_module_name));

View file

@ -3,11 +3,10 @@ use std::io;
use std::io::{stdin, stdout, BufRead, Read, StdinLock, StdoutLock, Write}; use std::io::{stdin, stdout, BufRead, Read, StdinLock, StdoutLock, Write};
use std::ops::Not; use std::ops::Not;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::str::FromStr; use std::str::FromStr;
use erg_common::consts::PYTHON_MODE; use erg_common::consts::PYTHON_MODE;
use erg_compiler::error::{CompileErrors, CompileWarnings}; use erg_compiler::erg_parser::ast::Module;
use erg_compiler::lower::ASTLowerer; use erg_compiler::lower::ASTLowerer;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::json; use serde_json::json;
@ -188,6 +187,18 @@ pub(crate) fn send_invalid_req_error() -> ELSResult<()> {
send_error(None, -32601, "received an invalid request") send_error(None, -32601, "received an invalid request")
} }
#[derive(Debug)]
pub struct AnalysisResult {
pub ast: Module,
pub artifact: IncompleteArtifact,
}
impl AnalysisResult {
pub fn new(ast: Module, artifact: IncompleteArtifact) -> Self {
Self { ast, artifact }
}
}
/// A Language Server, which can be used any object implementing `BuildRunnable` internally by passing it as a generic parameter. /// A Language Server, which can be used any object implementing `BuildRunnable` internally by passing it as a generic parameter.
#[derive(Debug)] #[derive(Debug)]
pub struct Server<Checker: BuildRunnable = HIRBuilder> { pub struct Server<Checker: BuildRunnable = HIRBuilder> {
@ -200,7 +211,7 @@ pub struct Server<Checker: BuildRunnable = HIRBuilder> {
pub(crate) file_cache: FileCache, pub(crate) file_cache: FileCache,
pub(crate) comp_cache: CompletionCache, pub(crate) comp_cache: CompletionCache,
pub(crate) modules: Dict<NormalizedUrl, ModuleContext>, pub(crate) modules: Dict<NormalizedUrl, ModuleContext>,
pub(crate) artifacts: Dict<NormalizedUrl, IncompleteArtifact>, pub(crate) artifacts: Dict<NormalizedUrl, AnalysisResult>,
pub(crate) current_sig: Option<Expr>, pub(crate) current_sig: Option<Expr>,
pub(crate) _checker: std::marker::PhantomData<Checker>, pub(crate) _checker: std::marker::PhantomData<Checker>,
} }
@ -541,24 +552,19 @@ impl<Checker: BuildRunnable> Server<Checker> {
} }
} }
pub(crate) fn get_lowerer(&self, path: &Path) -> Option<ASTLowerer> { pub(crate) fn get_lowerer(&mut self, uri: &NormalizedUrl) -> Option<ASTLowerer> {
let module = Rc::get_mut(&mut self.get_shared().unwrap().mod_cache.get_mut(path)?.module)?; let module = std::mem::take(self.modules.get_mut(uri)?);
let module = std::mem::take(module);
Some(ASTLowerer::new_with_ctx(module)) Some(ASTLowerer::new_with_ctx(module))
} }
pub(crate) fn restore_mod_ctx(&self, path: &Path, module: ModuleContext) { pub(crate) fn restore_mod_ctx(&mut self, uri: &NormalizedUrl, module: ModuleContext) {
self.get_shared() *self.modules.get_mut(uri).unwrap() = module;
.unwrap()
.mod_cache
.get_mut(path)
.unwrap()
.module = Rc::new(module);
} }
pub(crate) fn get_visitor(&self, uri: &NormalizedUrl) -> Option<HIRVisitor> { pub(crate) fn get_visitor(&self, uri: &NormalizedUrl) -> Option<HIRVisitor> {
self.artifacts self.artifacts
.get(uri)? .get(uri)?
.artifact
.object .object
.as_ref() .as_ref()
.map(|hir| HIRVisitor::new(hir, &self.file_cache, uri.clone())) .map(|hir| HIRVisitor::new(hir, &self.file_cache, uri.clone()))
@ -611,7 +617,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
ctxs.extend(singular_ctxs); ctxs.extend(singular_ctxs);
} }
} else { } else {
send_log("expr not found: {token}")?; _log!("expr not found: {token}");
} }
} }
Ok(ctxs) Ok(ctxs)