mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-27 11:59:05 +00:00
chore(els): improve completion
This commit is contained in:
parent
d1ee28db78
commit
7e9cef9c07
8 changed files with 225 additions and 190 deletions
|
@ -38,10 +38,11 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
||||||
.filter(|warn| warn.core.main_message.ends_with("is not used"))
|
.filter(|warn| warn.core.main_message.ends_with("is not used"))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
for warn in warns {
|
for warn in warns {
|
||||||
let Some(range) = util::loc_to_range(warn.core.loc) else {
|
let uri = util::normalize_url(Url::from_file_path(warn.input.full_path()).unwrap());
|
||||||
|
let Some(token) = self.file_cache.get_token(&uri, util::loc_to_pos(warn.core.loc).unwrap())? else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
match visitor.get_min_expr(range) {
|
match visitor.get_min_expr(&token) {
|
||||||
Some(Expr::Def(def)) => {
|
Some(Expr::Def(def)) => {
|
||||||
let Some(mut range) = util::loc_to_range(def.loc()) else {
|
let Some(mut range) = util::loc_to_range(def.loc()) else {
|
||||||
Self::send_log("range not found")?;
|
Self::send_log("range not found")?;
|
||||||
|
|
|
@ -27,10 +27,11 @@ fn mark_to_string(mark: MarkedString) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_u8_enum! { CompletionOrder;
|
impl_u8_enum! { CompletionOrder;
|
||||||
TypeMatched = 0,
|
TypeMatched,
|
||||||
Normal = 1,
|
SingularAttr,
|
||||||
Escaped = 2,
|
Normal,
|
||||||
DoubleEscaped = 3
|
Escaped,
|
||||||
|
DoubleEscaped,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompletionOrder {
|
impl CompletionOrder {
|
||||||
|
@ -59,6 +60,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
||||||
Self::send_log(format!("completion requested: {msg}"))?;
|
Self::send_log(format!("completion requested: {msg}"))?;
|
||||||
let params = CompletionParams::deserialize(&msg["params"])?;
|
let params = CompletionParams::deserialize(&msg["params"])?;
|
||||||
let uri = util::normalize_url(params.text_document_position.text_document.uri);
|
let uri = util::normalize_url(params.text_document_position.text_document.uri);
|
||||||
|
let path = util::uri_to_path(&uri);
|
||||||
let pos = params.text_document_position.position;
|
let pos = params.text_document_position.position;
|
||||||
let trigger = params
|
let trigger = params
|
||||||
.context
|
.context
|
||||||
|
@ -99,7 +101,9 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// don't show future defined items
|
// don't show future defined items
|
||||||
if name.ln_begin().unwrap_or(0) > pos.line + 1 {
|
if vi.def_loc.module.as_ref() == Some(&path)
|
||||||
|
&& name.ln_begin().unwrap_or(0) > pos.line + 1
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let readable_t = self
|
let readable_t = self
|
||||||
|
|
|
@ -24,6 +24,8 @@ pub struct FileCacheEntry {
|
||||||
pub token_stream: Option<TokenStream>,
|
pub token_stream: Option<TokenStream>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stores the contents of the file on-memory.
|
||||||
|
/// This struct can save changes in real-time & incrementally.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FileCache {
|
pub struct FileCache {
|
||||||
pub files: Shared<Dict<Url, FileCacheEntry>>,
|
pub files: Shared<Dict<Url, FileCacheEntry>>,
|
||||||
|
|
|
@ -2,12 +2,15 @@ use erg_common::traits::Locational;
|
||||||
use erg_common::Str;
|
use erg_common::Str;
|
||||||
use erg_compiler::erg_parser::token::Token;
|
use erg_compiler::erg_parser::token::Token;
|
||||||
use erg_compiler::hir::*;
|
use erg_compiler::hir::*;
|
||||||
use erg_compiler::ty::{HasType, Type};
|
|
||||||
use erg_compiler::varinfo::VarInfo;
|
use erg_compiler::varinfo::VarInfo;
|
||||||
use lsp_types::{Position, Range, Url};
|
use lsp_types::{Position, Url};
|
||||||
|
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
|
||||||
|
/// This struct provides:
|
||||||
|
/// * namespace where the cursor is located (`get_namespace`)
|
||||||
|
/// * cursor(`Token`) -> `Expr` mapping (`get_min_expr`)
|
||||||
|
/// * cursor(`Token`) -> `VarInfo` mapping (`get_info`)
|
||||||
pub struct HIRVisitor<'a> {
|
pub struct HIRVisitor<'a> {
|
||||||
hir: &'a HIR,
|
hir: &'a HIR,
|
||||||
uri: Url,
|
uri: Url,
|
||||||
|
@ -41,72 +44,6 @@ impl<'a> HIRVisitor<'a> {
|
||||||
matches!(chunk, Expr::Call(_) | Expr::Lambda(_) | Expr::Def(_) | Expr::ClassDef(_) if cond)
|
matches!(chunk, Expr::Call(_) | Expr::Lambda(_) | Expr::Def(_) | Expr::ClassDef(_) if cond)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_min_expr(&self, range: Range) -> Option<&Expr> {
|
|
||||||
self.get_min_expr_from_exprs(self.hir.module.iter(), range)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
fn get_min_expr_from_expr<'e>(&self, expr: &'e Expr, range: Range) -> Option<&'e Expr> {
|
|
||||||
match expr {
|
|
||||||
Expr::Def(def) => {
|
|
||||||
if let Some(expr) = self.get_min_expr_from_exprs(def.body.block.iter(), range) {
|
|
||||||
Some(expr)
|
|
||||||
} else if util::pos_in_loc(def, range.start) {
|
|
||||||
Some(expr)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Expr::Lambda(lambda) => {
|
|
||||||
if let Some(expr) = self.get_min_expr_from_exprs(lambda.body.iter(), range) {
|
|
||||||
Some(expr)
|
|
||||||
} else if util::pos_in_loc(lambda, range.start) {
|
|
||||||
Some(expr)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Expr::ClassDef(cdef) => {
|
|
||||||
if let Some(expr) = self.get_min_expr_from_exprs(cdef.methods.iter(), range) {
|
|
||||||
Some(expr)
|
|
||||||
} else if util::pos_in_loc(cdef, range.start) {
|
|
||||||
Some(expr)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Expr::PatchDef(pdef) => {
|
|
||||||
if let Some(expr) = self.get_min_expr_from_exprs(pdef.methods.iter(), range) {
|
|
||||||
Some(expr)
|
|
||||||
} else if util::pos_in_loc(pdef, range.start) {
|
|
||||||
Some(expr)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
other => {
|
|
||||||
if util::pos_in_loc(other, range.start) {
|
|
||||||
Some(expr)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_min_expr_from_exprs<'e>(
|
|
||||||
&self,
|
|
||||||
iter: impl Iterator<Item = &'e Expr>,
|
|
||||||
range: Range,
|
|
||||||
) -> Option<&'e Expr> {
|
|
||||||
for chunk in iter {
|
|
||||||
if let Some(expr) = self.get_min_expr_from_expr(chunk, range) {
|
|
||||||
return Some(expr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_expr_ns(&self, cur_ns: Vec<Str>, chunk: &Expr, pos: Position) -> Option<Vec<Str>> {
|
fn get_expr_ns(&self, cur_ns: Vec<Str>, chunk: &Expr, pos: Position) -> Option<Vec<Str>> {
|
||||||
if !(util::pos_in_loc(chunk, pos) || self.is_new_final_line(chunk, pos)) {
|
if !(util::pos_in_loc(chunk, pos) || self.is_new_final_line(chunk, pos)) {
|
||||||
return None;
|
return None;
|
||||||
|
@ -206,180 +143,228 @@ impl<'a> HIRVisitor<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the smallest expression containing `token`. Literals, accessors, containers, etc. are returned.
|
/// Returns the smallest expression containing `token`. Literals, accessors, containers, etc. are returned.
|
||||||
pub fn get_t(&self, token: &Token) -> Option<Type> {
|
pub fn get_min_expr(&self, token: &Token) -> Option<&Expr> {
|
||||||
for chunk in self.hir.module.iter() {
|
for chunk in self.hir.module.iter() {
|
||||||
if let Some(expr) = self.get_expr_t(chunk, token) {
|
if let Some(expr) = self.get_expr(chunk, token) {
|
||||||
return Some(expr);
|
return Some(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_expr_t_if_same<T: HasType>(&self, expr: &T, l: &Token, r: &Token) -> Option<Type> {
|
fn return_expr_if_same<'e>(&'e self, expr: &'e Expr, l: &Token, r: &Token) -> Option<&Expr> {
|
||||||
if self.strict_cmp {
|
if self.strict_cmp {
|
||||||
if l.deep_eq(r) {
|
if l.deep_eq(r) {
|
||||||
Some(expr.t())
|
Some(expr)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
} else if l == r {
|
} else if l == r {
|
||||||
Some(expr.t())
|
Some(expr)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_expr_t(&self, expr: &Expr, token: &Token) -> Option<Type> {
|
fn get_expr<'e>(&'e self, expr: &'e Expr, token: &Token) -> Option<&'e Expr> {
|
||||||
if expr.ln_end() < token.ln_begin() || expr.ln_begin() > token.ln_end() {
|
if expr.ln_end() < token.ln_begin() || expr.ln_begin() > token.ln_end() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Lit(lit) => self.return_expr_t_if_same(expr, &lit.token, token),
|
Expr::Lit(_) => Some(expr),
|
||||||
Expr::Accessor(acc) => self.get_acc_t(expr, acc, token),
|
Expr::Accessor(acc) => self.get_expr_from_acc(expr, acc, token),
|
||||||
Expr::BinOp(bin) => self.get_bin_t(bin, token),
|
Expr::BinOp(bin) => self.get_expr_from_bin(expr, bin, token),
|
||||||
Expr::UnaryOp(unary) => self.get_expr_t(&unary.expr, token),
|
Expr::UnaryOp(unary) => self.get_expr(&unary.expr, token),
|
||||||
Expr::Call(call) => self.get_call_t(call, token),
|
Expr::Call(call) => self.get_expr_from_call(expr, call, token),
|
||||||
Expr::ClassDef(class_def) => self.get_class_def_t(class_def, token),
|
Expr::ClassDef(class_def) => self.get_expr_from_class_def(class_def, token),
|
||||||
Expr::Def(def) => self.get_def_t(def, token),
|
Expr::Def(def) => self.get_expr_from_def(expr, def, token),
|
||||||
Expr::PatchDef(patch_def) => self.get_patch_def_t(patch_def, token),
|
Expr::PatchDef(patch_def) => self.get_expr_from_patch_def(expr, patch_def, token),
|
||||||
Expr::Lambda(lambda) => self.get_block_t(&lambda.body, token),
|
Expr::Lambda(lambda) => self.get_expr_from_lambda(expr, lambda, token),
|
||||||
Expr::Array(arr) => self.get_array_t(arr, token),
|
Expr::Array(arr) => self.get_expr_from_array(expr, arr, token),
|
||||||
Expr::Dict(dict) => self.get_dict_t(dict, token),
|
Expr::Dict(dict) => self.get_expr_from_dict(expr, dict, token),
|
||||||
Expr::Record(record) => self.get_record_t(record, token),
|
Expr::Record(record) => self.get_expr_from_record(expr, record, token),
|
||||||
Expr::Set(set) => self.get_set_t(set, token),
|
Expr::Set(set) => self.get_expr_from_set(expr, set, token),
|
||||||
Expr::Tuple(tuple) => self.get_tuple_t(tuple, token),
|
Expr::Tuple(tuple) => self.get_expr_from_tuple(expr, tuple, token),
|
||||||
Expr::TypeAsc(type_asc) => self.get_expr_t(&type_asc.expr, token),
|
Expr::TypeAsc(type_asc) => self.get_expr(&type_asc.expr, token),
|
||||||
Expr::Dummy(dummy) => self.get_dummy_t(dummy, token),
|
Expr::Dummy(dummy) => self.get_expr_from_dummy(dummy, token),
|
||||||
Expr::Compound(block) | Expr::Code(block) => self.get_block_t(block, token),
|
Expr::Compound(block) | Expr::Code(block) => self.get_expr_from_block(block, token),
|
||||||
Expr::ReDef(redef) => self.get_redef_t(expr, redef, token),
|
Expr::ReDef(redef) => self.get_expr_from_redef(expr, redef, token),
|
||||||
Expr::Import(_) => None,
|
Expr::Import(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_acc_t(&self, expr: &Expr, acc: &Accessor, token: &Token) -> Option<Type> {
|
fn get_expr_from_acc<'e>(
|
||||||
|
&'e self,
|
||||||
|
expr: &'e Expr,
|
||||||
|
acc: &'e Accessor,
|
||||||
|
token: &Token,
|
||||||
|
) -> Option<&Expr> {
|
||||||
match acc {
|
match acc {
|
||||||
Accessor::Ident(ident) => self.return_expr_t_if_same(expr, ident.name.token(), token),
|
Accessor::Ident(ident) => self.return_expr_if_same(expr, ident.name.token(), token),
|
||||||
Accessor::Attr(attr) => self
|
Accessor::Attr(attr) => self
|
||||||
.return_expr_t_if_same(expr, attr.ident.name.token(), token)
|
.return_expr_if_same(expr, attr.ident.name.token(), token)
|
||||||
.or_else(|| self.get_expr_t(&attr.obj, token)),
|
.or_else(|| self.get_expr(&attr.obj, token)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_bin_t(&self, bin: &BinOp, token: &Token) -> Option<Type> {
|
fn get_expr_from_bin<'e>(
|
||||||
self.get_expr_t(&bin.lhs, token)
|
&'e self,
|
||||||
.or_else(|| self.get_expr_t(&bin.rhs, token))
|
expr: &'e Expr,
|
||||||
|
bin: &'e BinOp,
|
||||||
|
token: &Token,
|
||||||
|
) -> Option<&Expr> {
|
||||||
|
if &bin.op == token {
|
||||||
|
return Some(expr);
|
||||||
|
}
|
||||||
|
self.get_expr(&bin.lhs, token)
|
||||||
|
.or_else(|| self.get_expr(&bin.rhs, token))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_call_t(&self, call: &Call, token: &Token) -> Option<Type> {
|
fn get_expr_from_call<'e>(
|
||||||
if call.args.paren.is_some() && call.ln_end() == token.ln_end() {
|
&'e self,
|
||||||
// call: `f(x)`, token: `)`
|
expr: &'e Expr,
|
||||||
return Some(call.t());
|
call: &'e Call,
|
||||||
}
|
token: &Token,
|
||||||
if let Some(attr) = &call.attr_name {
|
) -> Option<&Expr> {
|
||||||
if let Some(t) = self.return_expr_t_if_same(attr, attr.name.token(), token) {
|
// args: `(1, 2)`, token: `)`
|
||||||
return Some(t);
|
call.args
|
||||||
}
|
.paren
|
||||||
}
|
.as_ref()
|
||||||
self.get_expr_t(&call.obj, token)
|
.and_then(|(_, end)| self.return_expr_if_same(expr, end, token))
|
||||||
.or_else(|| self.get_args_t(&call.args, token))
|
.or_else(|| {
|
||||||
|
call.attr_name
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|attr| self.return_expr_if_same(expr, attr.name.token(), token))
|
||||||
|
})
|
||||||
|
.or_else(|| self.get_expr(&call.obj, token))
|
||||||
|
.or_else(|| self.get_expr_from_args(&call.args, token))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_args_t(&self, args: &Args, token: &Token) -> Option<Type> {
|
fn get_expr_from_args<'e>(&'e self, args: &'e Args, token: &Token) -> Option<&Expr> {
|
||||||
for arg in args.pos_args.iter() {
|
for arg in args.pos_args.iter() {
|
||||||
if let Some(expr) = self.get_expr_t(&arg.expr, token) {
|
if let Some(expr) = self.get_expr(&arg.expr, token) {
|
||||||
return Some(expr);
|
return Some(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(var) = &args.var_args {
|
if let Some(var) = &args.var_args {
|
||||||
if let Some(expr) = self.get_expr_t(&var.expr, token) {
|
if let Some(expr) = self.get_expr(&var.expr, token) {
|
||||||
return Some(expr);
|
return Some(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for arg in args.kw_args.iter() {
|
for arg in args.kw_args.iter() {
|
||||||
if let Some(expr) = self.get_expr_t(&arg.expr, token) {
|
if let Some(expr) = self.get_expr(&arg.expr, token) {
|
||||||
return Some(expr);
|
return Some(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_def_t(&self, def: &Def, token: &Token) -> Option<Type> {
|
fn get_expr_from_def<'e>(
|
||||||
self.return_expr_t_if_same(def.sig.ident(), def.sig.ident().name.token(), token)
|
&'e self,
|
||||||
.or_else(|| self.get_block_t(&def.body.block, token))
|
expr: &'e Expr,
|
||||||
|
def: &'e Def,
|
||||||
|
token: &Token,
|
||||||
|
) -> Option<&Expr> {
|
||||||
|
self.return_expr_if_same(expr, def.sig.ident().name.token(), token)
|
||||||
|
.or_else(|| self.get_expr_from_block(&def.body.block, token))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_class_def_t(&self, class_def: &ClassDef, token: &Token) -> Option<Type> {
|
fn get_expr_from_class_def<'e>(
|
||||||
|
&'e self,
|
||||||
|
class_def: &'e ClassDef,
|
||||||
|
token: &Token,
|
||||||
|
) -> Option<&Expr> {
|
||||||
class_def
|
class_def
|
||||||
.require_or_sup
|
.require_or_sup
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|req_sup| self.get_expr_t(req_sup, token))
|
.and_then(|req_sup| self.get_expr(req_sup, token))
|
||||||
.or_else(|| {
|
.or_else(|| self.get_expr_from_block(&class_def.methods, token))
|
||||||
self.return_expr_t_if_same(
|
|
||||||
class_def.sig.ident(),
|
|
||||||
class_def.sig.ident().name.token(),
|
|
||||||
token,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.or_else(|| self.get_block_t(&class_def.methods, token))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_block_t(&self, block: &Block, token: &Token) -> Option<Type> {
|
fn get_expr_from_block<'e>(&'e self, block: &'e Block, token: &Token) -> Option<&Expr> {
|
||||||
for chunk in block.iter() {
|
for chunk in block.iter() {
|
||||||
if let Some(expr) = self.get_expr_t(chunk, token) {
|
if let Some(expr) = self.get_expr(chunk, token) {
|
||||||
return Some(expr);
|
return Some(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_redef_t(&self, expr: &Expr, redef: &ReDef, token: &Token) -> Option<Type> {
|
fn get_expr_from_redef<'e>(
|
||||||
self.get_acc_t(expr, &redef.attr, token)
|
&'e self,
|
||||||
.or_else(|| self.get_block_t(&redef.block, token))
|
expr: &'e Expr,
|
||||||
|
redef: &'e ReDef,
|
||||||
|
token: &Token,
|
||||||
|
) -> Option<&Expr> {
|
||||||
|
self.get_expr_from_acc(expr, &redef.attr, token)
|
||||||
|
.or_else(|| self.get_expr_from_block(&redef.block, token))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_dummy_t(&self, dummy: &Dummy, token: &Token) -> Option<Type> {
|
fn get_expr_from_dummy<'e>(&'e self, dummy: &'e Dummy, token: &Token) -> Option<&Expr> {
|
||||||
for chunk in dummy.iter() {
|
for chunk in dummy.iter() {
|
||||||
if let Some(expr) = self.get_expr_t(chunk, token) {
|
if let Some(expr) = self.get_expr(chunk, token) {
|
||||||
return Some(expr);
|
return Some(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_patch_def_t(&self, patch_def: &PatchDef, token: &Token) -> Option<Type> {
|
fn get_expr_from_patch_def<'e>(
|
||||||
self.get_expr_t(&patch_def.base, token)
|
&'e self,
|
||||||
.or_else(|| {
|
expr: &'e Expr,
|
||||||
self.return_expr_t_if_same(
|
patch_def: &'e PatchDef,
|
||||||
patch_def.sig.ident(),
|
token: &Token,
|
||||||
patch_def.sig.ident().name.token(),
|
) -> Option<&Expr> {
|
||||||
token,
|
self.return_expr_if_same(expr, patch_def.sig.ident().name.token(), token)
|
||||||
)
|
.or_else(|| self.get_expr(&patch_def.base, token))
|
||||||
})
|
.or_else(|| self.get_expr_from_block(&patch_def.methods, token))
|
||||||
.or_else(|| self.get_block_t(&patch_def.methods, token))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_array_t(&self, arr: &Array, token: &Token) -> Option<Type> {
|
fn get_expr_from_lambda<'e>(
|
||||||
|
&'e self,
|
||||||
|
expr: &'e Expr,
|
||||||
|
lambda: &'e Lambda,
|
||||||
|
token: &Token,
|
||||||
|
) -> Option<&Expr> {
|
||||||
|
if util::pos_in_loc(&lambda.params, util::loc_to_pos(token.loc())?) {
|
||||||
|
return Some(expr);
|
||||||
|
}
|
||||||
|
self.get_expr_from_block(&lambda.body, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_expr_from_array<'e>(
|
||||||
|
&'e self,
|
||||||
|
expr: &'e Expr,
|
||||||
|
arr: &'e Array,
|
||||||
|
token: &Token,
|
||||||
|
) -> Option<&Expr> {
|
||||||
if arr.ln_end() == token.ln_end() {
|
if arr.ln_end() == token.ln_end() {
|
||||||
// arr: `[1, 2]`, token: `]`
|
// arr: `[1, 2]`, token: `]`
|
||||||
return Some(arr.t());
|
return Some(expr);
|
||||||
}
|
}
|
||||||
match arr {
|
match arr {
|
||||||
Array::Normal(arr) => self.get_args_t(&arr.elems, token),
|
Array::Normal(arr) => self.get_expr_from_args(&arr.elems, token),
|
||||||
_ => None, // todo!(),
|
_ => None, // todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_dict_t(&self, dict: &Dict, token: &Token) -> Option<Type> {
|
fn get_expr_from_dict<'e>(
|
||||||
|
&'e self,
|
||||||
|
expr: &'e Expr,
|
||||||
|
dict: &'e Dict,
|
||||||
|
token: &Token,
|
||||||
|
) -> Option<&Expr> {
|
||||||
if dict.ln_end() == token.ln_end() {
|
if dict.ln_end() == token.ln_end() {
|
||||||
// arr: `{...}`, token: `}`
|
// arr: `{...}`, token: `}`
|
||||||
return Some(dict.t());
|
return Some(expr);
|
||||||
}
|
}
|
||||||
match dict {
|
match dict {
|
||||||
Dict::Normal(dict) => {
|
Dict::Normal(dict) => {
|
||||||
for kv in &dict.kvs {
|
for kv in &dict.kvs {
|
||||||
if let Some(expr) = self.get_expr_t(&kv.key, token) {
|
if let Some(expr) = self
|
||||||
return Some(expr);
|
.get_expr(&kv.key, token)
|
||||||
} else if let Some(expr) = self.get_expr_t(&kv.value, token) {
|
.or_else(|| self.get_expr(&kv.value, token))
|
||||||
|
{
|
||||||
return Some(expr);
|
return Some(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -389,38 +374,55 @@ impl<'a> HIRVisitor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_record_t(&self, record: &Record, token: &Token) -> Option<Type> {
|
fn get_expr_from_record<'e>(
|
||||||
|
&'e self,
|
||||||
|
expr: &'e Expr,
|
||||||
|
record: &'e Record,
|
||||||
|
token: &Token,
|
||||||
|
) -> Option<&Expr> {
|
||||||
if record.ln_end() == token.ln_end() {
|
if record.ln_end() == token.ln_end() {
|
||||||
// arr: `{...}`, token: `}`
|
// arr: `{...}`, token: `}`
|
||||||
return Some(record.t());
|
return Some(expr);
|
||||||
}
|
}
|
||||||
for field in record.attrs.iter() {
|
for field in record.attrs.iter() {
|
||||||
if let Some(expr) = self.get_block_t(&field.body.block, token) {
|
if let Some(expr) = self.get_expr_from_block(&field.body.block, token) {
|
||||||
return Some(expr);
|
return Some(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_set_t(&self, set: &Set, token: &Token) -> Option<Type> {
|
fn get_expr_from_set<'e>(
|
||||||
|
&'e self,
|
||||||
|
expr: &'e Expr,
|
||||||
|
set: &'e Set,
|
||||||
|
token: &Token,
|
||||||
|
) -> Option<&Expr> {
|
||||||
if set.ln_end() == token.ln_end() {
|
if set.ln_end() == token.ln_end() {
|
||||||
// arr: `{...}`, token: `}`
|
// arr: `{...}`, token: `}`
|
||||||
return Some(set.t());
|
return Some(expr);
|
||||||
}
|
}
|
||||||
match set {
|
match set {
|
||||||
Set::Normal(set) => self.get_args_t(&set.elems, token),
|
Set::Normal(set) => self.get_expr_from_args(&set.elems, token),
|
||||||
_ => None, // todo!(),
|
_ => None, // todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_tuple_t(&self, tuple: &Tuple, token: &Token) -> Option<Type> {
|
fn get_expr_from_tuple<'e>(
|
||||||
|
&'e self,
|
||||||
|
expr: &'e Expr,
|
||||||
|
tuple: &'e Tuple,
|
||||||
|
token: &Token,
|
||||||
|
) -> Option<&Expr> {
|
||||||
match tuple {
|
match tuple {
|
||||||
Tuple::Normal(tuple) => {
|
Tuple::Normal(tuple) => {
|
||||||
if tuple.elems.paren.is_some() && tuple.ln_end() == token.ln_end() {
|
// arr: `(1, 2)`, token: `)`
|
||||||
// arr: `(1, 2)`, token: `)`
|
tuple
|
||||||
return Some(tuple.t());
|
.elems
|
||||||
}
|
.paren
|
||||||
self.get_args_t(&tuple.elems, token)
|
.as_ref()
|
||||||
|
.and_then(|(_, end)| self.return_expr_if_same(expr, end, token))
|
||||||
|
.or_else(|| self.get_expr_from_args(&tuple.elems, token))
|
||||||
} // _ => None, // todo!(),
|
} // _ => None, // todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,7 +139,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
||||||
// not found or not symbol, etc.
|
// not found or not symbol, etc.
|
||||||
None => {
|
None => {
|
||||||
if let Some(visitor) = self.get_visitor(&uri) {
|
if let Some(visitor) = self.get_visitor(&uri) {
|
||||||
if let Some(typ) = visitor.get_t(&token) {
|
if let Some(typ) = visitor.get_min_expr(&token) {
|
||||||
let typ = MarkedString::from_language_code(
|
let typ = MarkedString::from_language_code(
|
||||||
lang.into(),
|
lang.into(),
|
||||||
format!("{}: {typ}", token.content),
|
format!("{}: {typ}", token.content),
|
||||||
|
|
|
@ -17,6 +17,7 @@ use erg_compiler::artifact::{BuildRunnable, IncompleteArtifact};
|
||||||
use erg_compiler::build_hir::HIRBuilder;
|
use erg_compiler::build_hir::HIRBuilder;
|
||||||
use erg_compiler::context::{Context, ModuleContext};
|
use erg_compiler::context::{Context, ModuleContext};
|
||||||
use erg_compiler::module::{SharedCompilerResource, SharedModuleIndex};
|
use erg_compiler::module::{SharedCompilerResource, SharedModuleIndex};
|
||||||
|
use erg_compiler::ty::HasType;
|
||||||
|
|
||||||
use lsp_types::{
|
use lsp_types::{
|
||||||
ClientCapabilities, CodeActionKind, CodeActionOptions, CodeActionProviderCapability,
|
ClientCapabilities, CodeActionKind, CodeActionOptions, CodeActionProviderCapability,
|
||||||
|
@ -453,22 +454,23 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
||||||
.get_token_relatively(uri, attr_marker_pos, -1)?;
|
.get_token_relatively(uri, attr_marker_pos, -1)?;
|
||||||
if let Some(token) = maybe_token {
|
if let Some(token) = maybe_token {
|
||||||
Self::send_log(format!("token: {token}"))?;
|
Self::send_log(format!("token: {token}"))?;
|
||||||
let var_name = token.inspect();
|
let mut ctxs = vec![];
|
||||||
let ctxs = module.context.get_receiver_ctxs(var_name);
|
if let Some(visitor) = self.get_visitor(uri) {
|
||||||
if let Some(typ) = self
|
if let Some(expr) = visitor.get_min_expr(&token) {
|
||||||
.get_visitor(uri)
|
let type_ctxs = module
|
||||||
.and_then(|visitor| visitor.get_t(&token))
|
.context
|
||||||
{
|
.get_nominal_super_type_ctxs(expr.ref_t())
|
||||||
Self::send_log(format!("type: {typ}"))?;
|
.unwrap_or(vec![]);
|
||||||
let type_ctxs = module
|
ctxs.extend(type_ctxs);
|
||||||
.context
|
if let Ok(singular_ctx) = module
|
||||||
.get_nominal_super_type_ctxs(&typ)
|
.context
|
||||||
.unwrap_or(vec![]);
|
.get_singular_ctx_by_hir_expr(expr, &"".into())
|
||||||
Ok([ctxs, type_ctxs].concat())
|
{
|
||||||
} else {
|
ctxs.push(singular_ctx);
|
||||||
Self::send_log("failed to get the type")?;
|
}
|
||||||
Ok(ctxs)
|
}
|
||||||
}
|
}
|
||||||
|
Ok(ctxs)
|
||||||
} else {
|
} else {
|
||||||
Self::send_log("token not found")?;
|
Self::send_log("token not found")?;
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
|
|
|
@ -43,6 +43,30 @@ macro_rules! impl_display_for_enum {
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_u8_enum {
|
macro_rules! impl_u8_enum {
|
||||||
|
($Enum: ident; $($Variant: ident $(,)?)*) => {
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum $Enum {
|
||||||
|
$($Variant,)*
|
||||||
|
}
|
||||||
|
|
||||||
|
$crate::impl_display_from_debug!($Enum);
|
||||||
|
|
||||||
|
impl From<u8> for $Enum {
|
||||||
|
fn from(byte: u8) -> Self {
|
||||||
|
match byte {
|
||||||
|
$(v if v == $Enum::$Variant as u8 => $Enum::$Variant,)*
|
||||||
|
_ => todo!("unknown: {byte}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$Enum> for u8 {
|
||||||
|
fn from(op: $Enum) -> u8 {
|
||||||
|
op as u8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
($Enum: ident; $($Variant: ident = $val: expr $(,)?)*) => {
|
($Enum: ident; $($Variant: ident = $val: expr $(,)?)*) => {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
@ -72,7 +96,7 @@ macro_rules! impl_u8_enum {
|
||||||
90 <= (*self as u8) && (*self as u8) < 220
|
90 <= (*self as u8) && (*self as u8) < 220
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
|
|
@ -94,7 +94,7 @@ impl Context {
|
||||||
.or_else(|| self.get_outer().and_then(|ctx| ctx.get_var_kv(name)))
|
.or_else(|| self.get_outer().and_then(|ctx| ctx.get_var_kv(name)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_singular_ctx_by_hir_expr(
|
pub fn get_singular_ctx_by_hir_expr(
|
||||||
&self,
|
&self,
|
||||||
obj: &hir::Expr,
|
obj: &hir::Expr,
|
||||||
namespace: &Str,
|
namespace: &Str,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue