fix(els): incremental updating var-definition

This commit is contained in:
Shunsuke Shibayama 2023-06-21 15:08:03 +09:00
parent 4ece884ce3
commit 798f22afa4
4 changed files with 43 additions and 6 deletions

View file

@ -89,11 +89,29 @@ impl HIRDiff {
match diff {
ASTDiff::Deletion(idx) => Some(Self::Deletion(idx)),
ASTDiff::Addition(idx, expr) => {
let expr = lowerer.lower_expr(expr).ok()?;
let expr = lowerer
.lower_chunk(expr)
.map_err(|err| {
crate::_log!("err: {err}");
})
.ok()?;
Some(Self::Addition(idx, expr))
}
ASTDiff::Modification(idx, expr) => {
let expr = lowerer.lower_expr(expr).ok()?;
if let ast::Expr::Def(def)
| ast::Expr::ClassDef(ast::ClassDef { def, .. })
| ast::Expr::PatchDef(ast::PatchDef { def, .. }) = &expr
{
if let Some(name) = def.sig.name_as_str() {
lowerer.unregister(name);
}
}
let expr = lowerer
.lower_chunk(expr)
.map_err(|err| {
crate::_log!("err: {err}");
})
.ok()?;
Some(Self::Modification(idx, expr))
}
ASTDiff::Nop => Some(Self::Nop),

View file

@ -702,8 +702,13 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
}
"textDocument/didChange" => {
let params = DidChangeTextDocumentParams::deserialize(msg["params"].clone())?;
// check before updating, because `x.`/`x::` will result in an error
if TRIGGER_CHARS.contains(&&params.content_changes[0].text[..]) {
// Check before updating, because `x.`/`x::` will result in an error
// Checking should only be performed when needed for completion, i.e., when a trigger character is entered or at the beginning of a line
if TRIGGER_CHARS.contains(&&params.content_changes[0].text[..])
|| params.content_changes[0]
.range
.is_some_and(|r| r.start.character == 0)
{
let uri = NormalizedUrl::new(params.text_document.uri.clone());
// TODO: reset mutable dependent types
self.quick_check_file(uri)?;

View file

@ -533,6 +533,16 @@ impl Context {
let ctx = self.get_namespace(&namespace)?;
ctx.get_var_info(&typ.local_name())
}
pub fn unregister(&mut self, name: &str) -> Option<VarInfo> {
self.mono_types.remove(name);
self.poly_types.remove(name);
self.patches.remove(name);
self.erg_to_py_names.remove(name);
self.locals
.remove(name)
.or_else(|| self.locals.remove(name))
}
}
impl Context {

View file

@ -224,6 +224,10 @@ impl ASTLowerer {
pub fn get_var_info(&self, name: &str) -> Option<(&VarName, &VarInfo)> {
ContextProvider::get_var_info(self, name)
}
pub fn unregister(&mut self, name: &str) -> Option<VarInfo> {
self.module.context.unregister(name)
}
}
impl ASTLowerer {
@ -2373,7 +2377,7 @@ impl ASTLowerer {
// Call.obj == Accessor cannot be type inferred by itself (it can only be inferred with arguments)
// so turn off type checking (check=false)
pub fn lower_expr(&mut self, expr: ast::Expr) -> LowerResult<hir::Expr> {
fn lower_expr(&mut self, expr: ast::Expr) -> LowerResult<hir::Expr> {
log!(info "entered {}", fn_name!());
match expr {
ast::Expr::Literal(lit) => Ok(hir::Expr::Lit(self.lower_literal(lit)?)),
@ -2401,7 +2405,7 @@ impl ASTLowerer {
/// The meaning of TypeAscription changes between chunk and expr.
/// For example, `x: Int`, as expr, is `x` itself,
/// but as chunk, it declares that `x` is of type `Int`, and is valid even before `x` is defined.
pub(crate) fn lower_chunk(&mut self, chunk: ast::Expr) -> LowerResult<hir::Expr> {
pub fn lower_chunk(&mut self, chunk: ast::Expr) -> LowerResult<hir::Expr> {
log!(info "entered {}", fn_name!());
match chunk {
ast::Expr::Def(def) => Ok(hir::Expr::Def(self.lower_def(def)?)),