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"))
|
||||
.collect::<Vec<_>>();
|
||||
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;
|
||||
};
|
||||
match visitor.get_min_expr(range) {
|
||||
match visitor.get_min_expr(&token) {
|
||||
Some(Expr::Def(def)) => {
|
||||
let Some(mut range) = util::loc_to_range(def.loc()) else {
|
||||
Self::send_log("range not found")?;
|
||||
|
|
|
@ -27,10 +27,11 @@ fn mark_to_string(mark: MarkedString) -> String {
|
|||
}
|
||||
|
||||
impl_u8_enum! { CompletionOrder;
|
||||
TypeMatched = 0,
|
||||
Normal = 1,
|
||||
Escaped = 2,
|
||||
DoubleEscaped = 3
|
||||
TypeMatched,
|
||||
SingularAttr,
|
||||
Normal,
|
||||
Escaped,
|
||||
DoubleEscaped,
|
||||
}
|
||||
|
||||
impl CompletionOrder {
|
||||
|
@ -59,6 +60,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
|||
Self::send_log(format!("completion requested: {msg}"))?;
|
||||
let params = CompletionParams::deserialize(&msg["params"])?;
|
||||
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 trigger = params
|
||||
.context
|
||||
|
@ -99,7 +101,9 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
|||
continue;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
let readable_t = self
|
||||
|
|
|
@ -24,6 +24,8 @@ pub struct FileCacheEntry {
|
|||
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)]
|
||||
pub struct FileCache {
|
||||
pub files: Shared<Dict<Url, FileCacheEntry>>,
|
||||
|
|
|
@ -2,12 +2,15 @@ use erg_common::traits::Locational;
|
|||
use erg_common::Str;
|
||||
use erg_compiler::erg_parser::token::Token;
|
||||
use erg_compiler::hir::*;
|
||||
use erg_compiler::ty::{HasType, Type};
|
||||
use erg_compiler::varinfo::VarInfo;
|
||||
use lsp_types::{Position, Range, Url};
|
||||
use lsp_types::{Position, Url};
|
||||
|
||||
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> {
|
||||
hir: &'a HIR,
|
||||
uri: Url,
|
||||
|
@ -41,72 +44,6 @@ impl<'a> HIRVisitor<'a> {
|
|||
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>> {
|
||||
if !(util::pos_in_loc(chunk, pos) || self.is_new_final_line(chunk, pos)) {
|
||||
return None;
|
||||
|
@ -206,180 +143,228 @@ impl<'a> HIRVisitor<'a> {
|
|||
}
|
||||
|
||||
/// 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() {
|
||||
if let Some(expr) = self.get_expr_t(chunk, token) {
|
||||
if let Some(expr) = self.get_expr(chunk, token) {
|
||||
return Some(expr);
|
||||
}
|
||||
}
|
||||
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 l.deep_eq(r) {
|
||||
Some(expr.t())
|
||||
Some(expr)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else if l == r {
|
||||
Some(expr.t())
|
||||
Some(expr)
|
||||
} else {
|
||||
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() {
|
||||
return None;
|
||||
}
|
||||
match expr {
|
||||
Expr::Lit(lit) => self.return_expr_t_if_same(expr, &lit.token, token),
|
||||
Expr::Accessor(acc) => self.get_acc_t(expr, acc, token),
|
||||
Expr::BinOp(bin) => self.get_bin_t(bin, token),
|
||||
Expr::UnaryOp(unary) => self.get_expr_t(&unary.expr, token),
|
||||
Expr::Call(call) => self.get_call_t(call, token),
|
||||
Expr::ClassDef(class_def) => self.get_class_def_t(class_def, token),
|
||||
Expr::Def(def) => self.get_def_t(def, token),
|
||||
Expr::PatchDef(patch_def) => self.get_patch_def_t(patch_def, token),
|
||||
Expr::Lambda(lambda) => self.get_block_t(&lambda.body, token),
|
||||
Expr::Array(arr) => self.get_array_t(arr, token),
|
||||
Expr::Dict(dict) => self.get_dict_t(dict, token),
|
||||
Expr::Record(record) => self.get_record_t(record, token),
|
||||
Expr::Set(set) => self.get_set_t(set, token),
|
||||
Expr::Tuple(tuple) => self.get_tuple_t(tuple, token),
|
||||
Expr::TypeAsc(type_asc) => self.get_expr_t(&type_asc.expr, token),
|
||||
Expr::Dummy(dummy) => self.get_dummy_t(dummy, token),
|
||||
Expr::Compound(block) | Expr::Code(block) => self.get_block_t(block, token),
|
||||
Expr::ReDef(redef) => self.get_redef_t(expr, redef, token),
|
||||
Expr::Lit(_) => Some(expr),
|
||||
Expr::Accessor(acc) => self.get_expr_from_acc(expr, acc, token),
|
||||
Expr::BinOp(bin) => self.get_expr_from_bin(expr, bin, token),
|
||||
Expr::UnaryOp(unary) => self.get_expr(&unary.expr, token),
|
||||
Expr::Call(call) => self.get_expr_from_call(expr, call, token),
|
||||
Expr::ClassDef(class_def) => self.get_expr_from_class_def(class_def, token),
|
||||
Expr::Def(def) => self.get_expr_from_def(expr, def, token),
|
||||
Expr::PatchDef(patch_def) => self.get_expr_from_patch_def(expr, patch_def, token),
|
||||
Expr::Lambda(lambda) => self.get_expr_from_lambda(expr, lambda, token),
|
||||
Expr::Array(arr) => self.get_expr_from_array(expr, arr, token),
|
||||
Expr::Dict(dict) => self.get_expr_from_dict(expr, dict, token),
|
||||
Expr::Record(record) => self.get_expr_from_record(expr, record, token),
|
||||
Expr::Set(set) => self.get_expr_from_set(expr, set, token),
|
||||
Expr::Tuple(tuple) => self.get_expr_from_tuple(expr, tuple, token),
|
||||
Expr::TypeAsc(type_asc) => self.get_expr(&type_asc.expr, token),
|
||||
Expr::Dummy(dummy) => self.get_expr_from_dummy(dummy, token),
|
||||
Expr::Compound(block) | Expr::Code(block) => self.get_expr_from_block(block, token),
|
||||
Expr::ReDef(redef) => self.get_expr_from_redef(expr, redef, token),
|
||||
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 {
|
||||
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
|
||||
.return_expr_t_if_same(expr, attr.ident.name.token(), token)
|
||||
.or_else(|| self.get_expr_t(&attr.obj, token)),
|
||||
.return_expr_if_same(expr, attr.ident.name.token(), token)
|
||||
.or_else(|| self.get_expr(&attr.obj, token)),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_bin_t(&self, bin: &BinOp, token: &Token) -> Option<Type> {
|
||||
self.get_expr_t(&bin.lhs, token)
|
||||
.or_else(|| self.get_expr_t(&bin.rhs, token))
|
||||
fn get_expr_from_bin<'e>(
|
||||
&'e self,
|
||||
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> {
|
||||
if call.args.paren.is_some() && call.ln_end() == token.ln_end() {
|
||||
// call: `f(x)`, token: `)`
|
||||
return Some(call.t());
|
||||
}
|
||||
if let Some(attr) = &call.attr_name {
|
||||
if let Some(t) = self.return_expr_t_if_same(attr, attr.name.token(), token) {
|
||||
return Some(t);
|
||||
}
|
||||
}
|
||||
self.get_expr_t(&call.obj, token)
|
||||
.or_else(|| self.get_args_t(&call.args, token))
|
||||
fn get_expr_from_call<'e>(
|
||||
&'e self,
|
||||
expr: &'e Expr,
|
||||
call: &'e Call,
|
||||
token: &Token,
|
||||
) -> Option<&Expr> {
|
||||
// args: `(1, 2)`, token: `)`
|
||||
call.args
|
||||
.paren
|
||||
.as_ref()
|
||||
.and_then(|(_, end)| self.return_expr_if_same(expr, end, 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() {
|
||||
if let Some(expr) = self.get_expr_t(&arg.expr, token) {
|
||||
if let Some(expr) = self.get_expr(&arg.expr, token) {
|
||||
return Some(expr);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn get_def_t(&self, def: &Def, token: &Token) -> Option<Type> {
|
||||
self.return_expr_t_if_same(def.sig.ident(), def.sig.ident().name.token(), token)
|
||||
.or_else(|| self.get_block_t(&def.body.block, token))
|
||||
fn get_expr_from_def<'e>(
|
||||
&'e self,
|
||||
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
|
||||
.require_or_sup
|
||||
.as_ref()
|
||||
.and_then(|req_sup| self.get_expr_t(req_sup, token))
|
||||
.or_else(|| {
|
||||
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))
|
||||
.and_then(|req_sup| self.get_expr(req_sup, token))
|
||||
.or_else(|| self.get_expr_from_block(&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() {
|
||||
if let Some(expr) = self.get_expr_t(chunk, token) {
|
||||
if let Some(expr) = self.get_expr(chunk, token) {
|
||||
return Some(expr);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn get_redef_t(&self, expr: &Expr, redef: &ReDef, token: &Token) -> Option<Type> {
|
||||
self.get_acc_t(expr, &redef.attr, token)
|
||||
.or_else(|| self.get_block_t(&redef.block, token))
|
||||
fn get_expr_from_redef<'e>(
|
||||
&'e self,
|
||||
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() {
|
||||
if let Some(expr) = self.get_expr_t(chunk, token) {
|
||||
if let Some(expr) = self.get_expr(chunk, token) {
|
||||
return Some(expr);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn get_patch_def_t(&self, patch_def: &PatchDef, token: &Token) -> Option<Type> {
|
||||
self.get_expr_t(&patch_def.base, token)
|
||||
.or_else(|| {
|
||||
self.return_expr_t_if_same(
|
||||
patch_def.sig.ident(),
|
||||
patch_def.sig.ident().name.token(),
|
||||
token,
|
||||
)
|
||||
})
|
||||
.or_else(|| self.get_block_t(&patch_def.methods, token))
|
||||
fn get_expr_from_patch_def<'e>(
|
||||
&'e self,
|
||||
expr: &'e Expr,
|
||||
patch_def: &'e PatchDef,
|
||||
token: &Token,
|
||||
) -> Option<&Expr> {
|
||||
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))
|
||||
}
|
||||
|
||||
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() {
|
||||
// arr: `[1, 2]`, token: `]`
|
||||
return Some(arr.t());
|
||||
return Some(expr);
|
||||
}
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
// arr: `{...}`, token: `}`
|
||||
return Some(dict.t());
|
||||
return Some(expr);
|
||||
}
|
||||
match dict {
|
||||
Dict::Normal(dict) => {
|
||||
for kv in &dict.kvs {
|
||||
if let Some(expr) = self.get_expr_t(&kv.key, token) {
|
||||
return Some(expr);
|
||||
} else if let Some(expr) = self.get_expr_t(&kv.value, token) {
|
||||
if let Some(expr) = self
|
||||
.get_expr(&kv.key, token)
|
||||
.or_else(|| self.get_expr(&kv.value, token))
|
||||
{
|
||||
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() {
|
||||
// arr: `{...}`, token: `}`
|
||||
return Some(record.t());
|
||||
return Some(expr);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
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() {
|
||||
// arr: `{...}`, token: `}`
|
||||
return Some(set.t());
|
||||
return Some(expr);
|
||||
}
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
Tuple::Normal(tuple) => {
|
||||
if tuple.elems.paren.is_some() && tuple.ln_end() == token.ln_end() {
|
||||
// arr: `(1, 2)`, token: `)`
|
||||
return Some(tuple.t());
|
||||
}
|
||||
self.get_args_t(&tuple.elems, token)
|
||||
tuple
|
||||
.elems
|
||||
.paren
|
||||
.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!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,7 +139,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
|||
// not found or not symbol, etc.
|
||||
None => {
|
||||
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(
|
||||
lang.into(),
|
||||
format!("{}: {typ}", token.content),
|
||||
|
|
|
@ -17,6 +17,7 @@ use erg_compiler::artifact::{BuildRunnable, IncompleteArtifact};
|
|||
use erg_compiler::build_hir::HIRBuilder;
|
||||
use erg_compiler::context::{Context, ModuleContext};
|
||||
use erg_compiler::module::{SharedCompilerResource, SharedModuleIndex};
|
||||
use erg_compiler::ty::HasType;
|
||||
|
||||
use lsp_types::{
|
||||
ClientCapabilities, CodeActionKind, CodeActionOptions, CodeActionProviderCapability,
|
||||
|
@ -453,22 +454,23 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
|||
.get_token_relatively(uri, attr_marker_pos, -1)?;
|
||||
if let Some(token) = maybe_token {
|
||||
Self::send_log(format!("token: {token}"))?;
|
||||
let var_name = token.inspect();
|
||||
let ctxs = module.context.get_receiver_ctxs(var_name);
|
||||
if let Some(typ) = self
|
||||
.get_visitor(uri)
|
||||
.and_then(|visitor| visitor.get_t(&token))
|
||||
{
|
||||
Self::send_log(format!("type: {typ}"))?;
|
||||
let mut ctxs = vec![];
|
||||
if let Some(visitor) = self.get_visitor(uri) {
|
||||
if let Some(expr) = visitor.get_min_expr(&token) {
|
||||
let type_ctxs = module
|
||||
.context
|
||||
.get_nominal_super_type_ctxs(&typ)
|
||||
.get_nominal_super_type_ctxs(expr.ref_t())
|
||||
.unwrap_or(vec![]);
|
||||
Ok([ctxs, type_ctxs].concat())
|
||||
} else {
|
||||
Self::send_log("failed to get the type")?;
|
||||
Ok(ctxs)
|
||||
ctxs.extend(type_ctxs);
|
||||
if let Ok(singular_ctx) = module
|
||||
.context
|
||||
.get_singular_ctx_by_hir_expr(expr, &"".into())
|
||||
{
|
||||
ctxs.push(singular_ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(ctxs)
|
||||
} else {
|
||||
Self::send_log("token not found")?;
|
||||
Ok(vec![])
|
||||
|
|
|
@ -43,6 +43,30 @@ macro_rules! impl_display_for_enum {
|
|||
|
||||
#[macro_export]
|
||||
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 $(,)?)*) => {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[repr(u8)]
|
||||
|
@ -72,7 +96,7 @@ macro_rules! impl_u8_enum {
|
|||
90 <= (*self as u8) && (*self as u8) < 220
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
|
|
@ -94,7 +94,7 @@ impl Context {
|
|||
.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,
|
||||
obj: &hir::Expr,
|
||||
namespace: &Str,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue