fix(els): hover

* show type difinitions
This commit is contained in:
Shunsuke Shibayama 2023-08-16 19:57:55 +09:00
parent efbad81475
commit 6a925f38bd
3 changed files with 86 additions and 15 deletions

View file

@ -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)
);

View file

@ -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> {

View file

@ -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)]