mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-04 10:49:54 +00:00
fix(els): hover
* show type difinitions
This commit is contained in:
parent
efbad81475
commit
6a925f38bd
3 changed files with 86 additions and 15 deletions
|
@ -4,7 +4,6 @@ use erg_common::trim_eliminate_top_indent;
|
|||
use erg_compiler::artifact::BuildRunnable;
|
||||
use erg_compiler::erg_parser::parse::Parsable;
|
||||
use erg_compiler::erg_parser::token::{Token, TokenCategory, TokenKind};
|
||||
use erg_compiler::ty::HasType;
|
||||
use erg_compiler::varinfo::{AbsLocation, VarInfo};
|
||||
|
||||
use lsp_types::{Hover, HoverContents, HoverParams, MarkedString, Url};
|
||||
|
@ -187,7 +186,7 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
|
|||
|
||||
fn show_type_defs(&mut self, vi: &VarInfo, contents: &mut Vec<MarkedString>) -> ELSResult<()> {
|
||||
let mut defs = "".to_string();
|
||||
for inner_t in vi.t.inner_ts() {
|
||||
for inner_t in vi.t.contained_ts() {
|
||||
if let Some(path) = &vi.def_loc.module {
|
||||
let Ok(def_uri) = util::NormalizedUrl::try_from(path.as_path()) else {
|
||||
continue;
|
||||
|
@ -199,13 +198,14 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
|
|||
continue;
|
||||
};
|
||||
if let Some((_, vi)) = module.context.get_type_info(&inner_t) {
|
||||
if let Some(uri) =
|
||||
vi.def_loc.module.as_ref().and_then(|path| {
|
||||
Some(util::denormalize(Url::parse(path.to_str()?).ok()?))
|
||||
})
|
||||
if let Some(url) = vi
|
||||
.def_loc
|
||||
.module
|
||||
.as_ref()
|
||||
.and_then(|path| Url::from_file_path(path).ok())
|
||||
{
|
||||
defs += &format!(
|
||||
"[{}]({uri}#L{}) ",
|
||||
"[{}]({url}#L{}) ",
|
||||
inner_t.local_name(),
|
||||
vi.def_loc.loc.ln_begin().unwrap_or(1)
|
||||
);
|
||||
|
|
|
@ -1323,6 +1323,7 @@ impl HasType for Type {
|
|||
}
|
||||
fn inner_ts(&self) -> Vec<Type> {
|
||||
match self {
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().inner_ts(),
|
||||
Self::Ref(t) => {
|
||||
vec![t.as_ref().clone()]
|
||||
}
|
||||
|
@ -1330,7 +1331,6 @@ impl HasType for Type {
|
|||
// REVIEW:
|
||||
vec![before.as_ref().clone()]
|
||||
}
|
||||
// Self::And(ts) | Self::Or(ts) => ,
|
||||
Self::Subr(sub) => sub
|
||||
.default_params
|
||||
.iter()
|
||||
|
@ -2242,6 +2242,8 @@ impl Type {
|
|||
/// ```
|
||||
pub fn namespace(&self) -> Str {
|
||||
match self {
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().namespace(),
|
||||
Self::Refinement(refine) => refine.t.namespace(),
|
||||
Self::Mono(name) | Self::Poly { name, .. } => {
|
||||
let namespaces = name.split_with(&[".", "::"]);
|
||||
if namespaces.len() > 1 {
|
||||
|
@ -2270,6 +2272,8 @@ impl Type {
|
|||
/// ```
|
||||
pub fn local_name(&self) -> Str {
|
||||
match self {
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().local_name(),
|
||||
Self::Refinement(refine) => refine.t.local_name(),
|
||||
Self::Mono(name) | Self::Poly { name, .. } => {
|
||||
let namespaces = name.split_with(&[".", "::"]);
|
||||
Str::rc(namespaces.last().unwrap())
|
||||
|
@ -2281,25 +2285,27 @@ impl Type {
|
|||
/// assert!((A and B).contains_intersec(B))
|
||||
pub fn contains_intersec(&self, typ: &Type) -> bool {
|
||||
match self {
|
||||
Type::And(t1, t2) => t1.contains_intersec(typ) || t2.contains_intersec(typ),
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().contains_intersec(typ),
|
||||
Self::Refinement(refine) => refine.t.contains_intersec(typ),
|
||||
Self::And(t1, t2) => t1.contains_intersec(typ) || t2.contains_intersec(typ),
|
||||
_ => self == typ,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn union_pair(&self) -> Option<(Type, Type)> {
|
||||
match self {
|
||||
Type::FreeVar(fv) if fv.is_linked() => fv.crack().union_pair(),
|
||||
Type::Refinement(refine) => refine.t.union_pair(),
|
||||
Type::Or(t1, t2) => Some((*t1.clone(), *t2.clone())),
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().union_pair(),
|
||||
Self::Refinement(refine) => refine.t.union_pair(),
|
||||
Self::Or(t1, t2) => Some((*t1.clone(), *t2.clone())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn union_types(&self) -> Vec<Type> {
|
||||
match self {
|
||||
Type::FreeVar(fv) if fv.is_linked() => fv.crack().union_types(),
|
||||
Type::Refinement(refine) => refine.t.union_types(),
|
||||
Type::Or(t1, t2) => {
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().union_types(),
|
||||
Self::Refinement(refine) => refine.t.union_types(),
|
||||
Self::Or(t1, t2) => {
|
||||
let mut types = t1.union_types();
|
||||
types.extend(t2.union_types());
|
||||
types
|
||||
|
@ -3307,6 +3313,59 @@ impl Type {
|
|||
_ => set![self.clone()],
|
||||
}
|
||||
}
|
||||
|
||||
/// ```erg
|
||||
/// Int.contained_ts() == {Int}
|
||||
/// Array(Array(Int)).contained_ts() == {Array(Int), Int}
|
||||
/// (Int or Str).contained_ts() == {Int, Str}
|
||||
/// ```
|
||||
pub fn contained_ts(&self) -> Set<Type> {
|
||||
match self {
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().contained_ts(),
|
||||
Self::FreeVar(fv) if fv.constraint_is_sandwiched() => {
|
||||
let (sub, sup) = fv.get_subsup().unwrap();
|
||||
sub.contained_ts().union(&sup.contained_ts())
|
||||
}
|
||||
Self::Refinement(refine) => refine.t.contained_ts(),
|
||||
Self::Ref(t) => t.contained_ts(),
|
||||
Self::RefMut { before, .. } => before.contained_ts(),
|
||||
Self::Subr(sub) => {
|
||||
let mut ts = set! {};
|
||||
for nd in sub.non_default_params.iter() {
|
||||
ts.extend(nd.typ().contained_ts());
|
||||
}
|
||||
if let Some(var) = sub.var_params.as_ref() {
|
||||
ts.extend(var.typ().contained_ts());
|
||||
}
|
||||
for d in sub.default_params.iter() {
|
||||
ts.extend(d.typ().contained_ts());
|
||||
}
|
||||
ts.extend(sub.return_t.contained_ts());
|
||||
ts
|
||||
}
|
||||
Self::Callable { param_ts, .. } => {
|
||||
param_ts.iter().flat_map(|t| t.contained_ts()).collect()
|
||||
}
|
||||
Self::And(l, r) | Self::Or(l, r) => l.contained_ts().union(&r.contained_ts()),
|
||||
Self::Not(t) => t.contained_ts(),
|
||||
Self::Bounded { sub, sup } => sub.contained_ts().union(&sup.contained_ts()),
|
||||
Self::Quantified(ty) | Self::Structural(ty) => ty.contained_ts(),
|
||||
Self::Record(rec) => rec.values().flat_map(|t| t.contained_ts()).collect(),
|
||||
Self::Proj { lhs, .. } => lhs.contained_ts(),
|
||||
Self::ProjCall { lhs, args, .. } => {
|
||||
let mut ts = set! {};
|
||||
ts.extend(lhs.contained_ts());
|
||||
ts.extend(args.iter().flat_map(|tp| tp.contained_ts()));
|
||||
ts
|
||||
}
|
||||
Self::Poly { params, .. } => {
|
||||
let mut ts = set! { self.clone() };
|
||||
ts.extend(params.iter().flat_map(|tp| tp.contained_ts()));
|
||||
ts
|
||||
}
|
||||
_ => set! { self.clone() },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ReplaceTable<'t> {
|
||||
|
|
|
@ -1438,6 +1438,18 @@ impl TyParam {
|
|||
_ => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contained_ts(&self) -> Set<Type> {
|
||||
match self {
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().contained_ts(),
|
||||
Self::Type(t) => t.contained_ts(),
|
||||
Self::Value(ValueObj::Type(t)) => t.typ().contained_ts(),
|
||||
Self::App { args, .. } => args
|
||||
.iter()
|
||||
.fold(set! {}, |acc, p| acc.concat(p.contained_ts())),
|
||||
_ => set! {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue