Skip to content

Commit

Permalink
chore(els): improve method completion
Browse files Browse the repository at this point in the history
  • Loading branch information
mtshiba committed Oct 11, 2024
1 parent e7d01b8 commit 0e53191
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 21 deletions.
8 changes: 7 additions & 1 deletion crates/els/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,10 +289,16 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
}
if let Some((mut lowerer, mut irs)) = self.steal_lowerer(&uri) {
if let Some((hir_diff, hir)) =
HIRDiff::new(ast_diff, &mut lowerer).zip(irs.hir.as_mut())
HIRDiff::new(ast_diff.clone(), &mut lowerer).zip(irs.hir.as_mut())
{
crate::_log!(self, "hir_diff: {hir_diff}");
hir_diff.update(hir);
if let Some(ast) = irs.ast.as_mut() {
ast_diff.update(ast);
}
}
if let Some(hir) = irs.hir.as_mut() {
HIRDiff::fix(&new, &mut hir.module, &mut lowerer);
}
self.restore_lowerer(uri, lowerer, irs);
}
Expand Down
63 changes: 51 additions & 12 deletions crates/els/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use erg_compiler::erg_parser::ast::Module;
use erg_compiler::hir;
use erg_compiler::hir::HIR;
use erg_compiler::lower::ASTLowerer;
use erg_compiler::ty::HasType;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ASTDiff {
Expand Down Expand Up @@ -67,6 +68,29 @@ impl ASTDiff {
pub const fn is_nop(&self) -> bool {
matches!(self, Self::Nop)
}

pub fn update(self, mut old: impl DerefMut<Target = ast::Module>) {
match self {
Self::Addition(idx, expr) => {
if idx > old.len() {
old.push(expr);
} else {
old.insert(idx, expr);
}
}
Self::Deletion(usize) => {
if old.get(usize).is_some() {
old.remove(usize);
}
}
Self::Modification(idx, expr) => {
if let Some(old_expr) = old.get_mut(idx) {
*old_expr = expr;
}
}
Self::Nop => {}
}
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
Expand All @@ -93,12 +117,10 @@ impl HIRDiff {
match diff {
ASTDiff::Deletion(idx) => Some(Self::Deletion(idx)),
ASTDiff::Addition(idx, expr) => {
let expr = lowerer
.lower_chunk(expr, None)
.map_err(|_err| {
// crate::_log!(self, "err: {err}");
})
.ok()?;
let expr = match lowerer.lower_and_resolve_chunk(expr, None) {
Ok(expr) => expr,
Err((opt_expr, _err)) => opt_expr?,
};
Some(Self::Addition(idx, expr))
}
ASTDiff::Modification(idx, expr) => {
Expand All @@ -110,12 +132,10 @@ impl HIRDiff {
lowerer.unregister(name);
}
}
let expr = lowerer
.lower_chunk(expr, None)
.map_err(|_err| {
// crate::_log!(self, "err: {err}");
})
.ok()?;
let expr = match lowerer.lower_and_resolve_chunk(expr, None) {
Ok(expr) => expr,
Err((opt_expr, _err)) => opt_expr?,
};
Some(Self::Modification(idx, expr))
}
ASTDiff::Nop => Some(Self::Nop),
Expand Down Expand Up @@ -144,4 +164,23 @@ impl HIRDiff {
Self::Nop => {}
}
}

pub fn fix(ast: &ast::Module, hir: &mut hir::Module, lowerer: &mut ASTLowerer) -> usize {
let mut fixed = 0;
for (ast_chunk, chunk) in ast.iter().zip(hir.iter_mut()) {
if ast_chunk.name() != chunk.name() {
continue;
}
if chunk.ref_t().contains_failure() {
match lowerer.lower_and_resolve_chunk(ast_chunk.clone(), None) {
Ok(expr) | Err((Some(expr), _)) => {
*chunk = expr;
fixed += 1;
}
_ => {}
}
}
}
fixed
}
}
6 changes: 5 additions & 1 deletion crates/erg_compiler/context/generalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1529,7 +1529,11 @@ impl Context {
/// Resolution should start at a deeper level.
/// For example, if it is a lambda function, the body should be checked before the signature.
/// However, a binop call error, etc., is more important then binop operands.
fn resolve_expr_t(&self, expr: &mut hir::Expr, qnames: &Set<Str>) -> TyCheckResult<()> {
pub(crate) fn resolve_expr_t(
&self,
expr: &mut hir::Expr,
qnames: &Set<Str>,
) -> TyCheckResult<()> {
match expr {
hir::Expr::Literal(_) => Ok(()),
hir::Expr::Accessor(acc) => {
Expand Down
2 changes: 1 addition & 1 deletion crates/erg_compiler/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3008,7 +3008,7 @@ impl Expr {
match self {
Self::Literal(_) => "literal",
Self::Accessor(_) => "accessor",
Self::List(_) => "array",
Self::List(_) => "list",
Self::Tuple(_) => "tuple",
Self::Dict(_) => "dict",
Self::Set(_) => "set",
Expand Down
20 changes: 19 additions & 1 deletion crates/erg_compiler/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3606,7 +3606,7 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
/// 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 fn lower_chunk(
pub(crate) fn lower_chunk(
&mut self,
chunk: ast::Expr,
expect: Option<&Type>,
Expand All @@ -3633,6 +3633,24 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
}
}

pub fn lower_and_resolve_chunk(
&mut self,
chunk: ast::Expr,
expect: Option<&Type>,
) -> FailableOption<hir::Expr> {
match self.lower_chunk(chunk, expect) {
Ok(mut chunk) => {
let _ = self.module.context.resolve_expr_t(&mut chunk, &set! {});
Ok(chunk)
}
Err((Some(mut chunk), errs)) => {
let _ = self.module.context.resolve_expr_t(&mut chunk, &set! {});
Err((Some(chunk), errs))
}
Err((None, errs)) => Err((None, errs)),
}
}

fn lower_block(
&mut self,
ast_block: ast::Block,
Expand Down
95 changes: 90 additions & 5 deletions crates/erg_parser/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use std::borrow::Borrow;
use std::fmt;
use std::fmt::Write as _;
use std::hash::{Hash, Hasher};

use erg_common::consts::ERG_MODE;
use erg_common::error::Location;
Expand Down Expand Up @@ -2559,13 +2560,28 @@ impl ConstBlock {
}

#[pyclass(get_all, set_all)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug)]
pub struct ConstDefBody {
pub op: Token,
pub block: ConstBlock,
pub id: DefId,
}

impl PartialEq for ConstDefBody {
fn eq(&self, other: &Self) -> bool {
self.op == other.op && self.block == other.block
}
}

impl Eq for ConstDefBody {}

impl Hash for ConstDefBody {
fn hash<H: Hasher>(&self, state: &mut H) {
self.op.hash(state);
self.block.hash(state);
}
}

impl_locational!(ConstDefBody, lossy op, block);

#[pymethods]
Expand Down Expand Up @@ -2613,14 +2629,30 @@ impl ConstDef {
}

#[pyclass]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug)]
pub struct ConstLambda {
pub sig: Box<LambdaSignature>,
pub op: Token,
pub body: ConstBlock,
pub id: DefId,
}

impl PartialEq for ConstLambda {
fn eq(&self, other: &Self) -> bool {
self.sig == other.sig && self.op == other.op && self.body == other.body
}
}

impl Eq for ConstLambda {}

impl Hash for ConstLambda {
fn hash<H: Hasher>(&self, state: &mut H) {
self.sig.hash(state);
self.op.hash(state);
self.body.hash(state);
}
}

impl NestedDisplay for ConstLambda {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
write!(f, "({}) {} {}", self.sig, self.op.content, self.body)
Expand Down Expand Up @@ -5495,6 +5527,8 @@ impl LambdaSignature {
}
}

/// Definition ID.
/// IDs are comparable, but `Def`s with different IDs are equal if the node contents are the same.
#[pyclass(subclass)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct DefId(pub usize);
Expand All @@ -5506,7 +5540,7 @@ impl DefId {
}

#[pyclass(get_all, set_all)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug)]
pub struct Lambda {
pub sig: LambdaSignature,
/// for detecting func/proc
Expand All @@ -5515,6 +5549,22 @@ pub struct Lambda {
pub id: DefId,
}

impl PartialEq for Lambda {
fn eq(&self, other: &Self) -> bool {
self.sig == other.sig && self.op == other.op && self.body == other.body
}
}

impl Eq for Lambda {}

impl Hash for Lambda {
fn hash<H: Hasher>(&self, state: &mut H) {
self.sig.hash(state);
self.op.hash(state);
self.body.hash(state);
}
}

impl NestedDisplay for Lambda {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
writeln!(f, "{} {}", self.sig, self.op.content)?;
Expand Down Expand Up @@ -5762,7 +5812,7 @@ impl DefKind {
}

#[pyclass(get_all, set_all)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug)]
pub struct DefBody {
pub op: Token,
pub block: Block,
Expand All @@ -5771,6 +5821,21 @@ pub struct DefBody {

impl_locational!(DefBody, lossy op, block);

impl PartialEq for DefBody {
fn eq(&self, other: &Self) -> bool {
self.op == other.op && self.block == other.block
}
}

impl Eq for DefBody {}

impl Hash for DefBody {
fn hash<H: Hasher>(&self, state: &mut H) {
self.op.hash(state);
self.block.hash(state);
}
}

#[pymethods]
impl DefBody {
#[staticmethod]
Expand Down Expand Up @@ -5896,7 +5961,7 @@ impl ReDef {
/// f(a) = ...
/// ```
#[pyclass]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone)]
pub struct Methods {
pub id: DefId,
pub class: TypeSpec,
Expand All @@ -5905,6 +5970,26 @@ pub struct Methods {
pub attrs: ClassAttrs,
}

impl PartialEq for Methods {
fn eq(&self, other: &Self) -> bool {
self.class == other.class
&& self.class_as_expr == other.class_as_expr
&& self.vis == other.vis
&& self.attrs == other.attrs
}
}

impl Eq for Methods {}

impl Hash for Methods {
fn hash<H: Hasher>(&self, state: &mut H) {
self.class.hash(state);
self.class_as_expr.hash(state);
self.vis.hash(state);
self.attrs.hash(state);
}
}

impl NestedDisplay for Methods {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
writeln!(f, "{}{}", self.class, self.vis)?;
Expand Down

0 comments on commit 0e53191

Please sign in to comment.