feat(els): display type bounds as inlay hints

This commit is contained in:
Shunsuke Shibayama 2023-02-19 02:39:03 +09:00
parent 855d47f02c
commit 7103c9f3bb
6 changed files with 123 additions and 57 deletions

View file

@ -1,6 +1,8 @@
use std::mem;
use erg_common::set::Set;
use erg_common::traits::{Locational, Stream};
use erg_common::Str;
use erg_common::{assume_unreachable, fn_name};
use erg_common::{dict, set};
#[allow(unused_imports)]
@ -728,7 +730,7 @@ impl Context {
self.level = 0;
let mut errs = TyCheckErrors::empty();
for chunk in hir.module.iter_mut() {
if let Err(es) = self.resolve_expr_t(chunk) {
if let Err(es) = self.resolve_expr_t(chunk, &mut set! {}) {
errs.extend(es);
}
}
@ -762,38 +764,50 @@ impl Context {
self.methods_list = methods_list;
}
fn resolve_params_t(&self, params: &mut hir::Params) -> TyCheckResult<()> {
fn resolve_params_t(
&self,
params: &mut hir::Params,
qvars: &mut Set<Str>,
) -> TyCheckResult<()> {
for param in params.non_defaults.iter_mut() {
param.vi.t = self.deref_tyvar(mem::take(&mut param.vi.t), Contravariant, param)?;
if !qvars.contains(&param.vi.t.qual_name()) {
param.vi.t = self.deref_tyvar(mem::take(&mut param.vi.t), Contravariant, param)?;
}
}
if let Some(var_params) = &mut params.var_params {
var_params.vi.t = self.deref_tyvar(
mem::take(&mut var_params.vi.t),
Contravariant,
var_params.as_ref(),
)?;
if !qvars.contains(&var_params.vi.t.qual_name()) {
var_params.vi.t = self.deref_tyvar(
mem::take(&mut var_params.vi.t),
Contravariant,
var_params.as_ref(),
)?;
}
}
for param in params.defaults.iter_mut() {
param.sig.vi.t =
self.deref_tyvar(mem::take(&mut param.sig.vi.t), Contravariant, param)?;
self.resolve_expr_t(&mut param.default_val)?;
if !qvars.contains(&param.sig.vi.t.qual_name()) {
param.sig.vi.t =
self.deref_tyvar(mem::take(&mut param.sig.vi.t), Contravariant, param)?;
}
self.resolve_expr_t(&mut param.default_val, qvars)?;
}
Ok(())
}
fn resolve_expr_t(&self, expr: &mut hir::Expr) -> TyCheckResult<()> {
fn resolve_expr_t(&self, expr: &mut hir::Expr, qvars: &mut Set<Str>) -> TyCheckResult<()> {
match expr {
hir::Expr::Lit(_) => Ok(()),
hir::Expr::Accessor(acc) => {
let variance = if acc.var_info().kind.is_parameter() {
Contravariant
} else {
Covariant
};
let t = mem::take(acc.ref_mut_t());
*acc.ref_mut_t() = self.deref_tyvar(t, variance, acc)?;
if !qvars.contains(&acc.ref_t().qual_name()) {
let variance = if acc.var_info().kind.is_parameter() {
Contravariant
} else {
Covariant
};
let t = mem::take(acc.ref_mut_t());
*acc.ref_mut_t() = self.deref_tyvar(t, variance, acc)?;
}
if let hir::Accessor::Attr(attr) = acc {
self.resolve_expr_t(&mut attr.obj)?;
self.resolve_expr_t(&mut attr.obj, qvars)?;
}
Ok(())
}
@ -801,14 +815,14 @@ impl Context {
hir::Array::Normal(arr) => {
arr.t = self.deref_tyvar(mem::take(&mut arr.t), Covariant, arr)?;
for elem in arr.elems.pos_args.iter_mut() {
self.resolve_expr_t(&mut elem.expr)?;
self.resolve_expr_t(&mut elem.expr, qvars)?;
}
Ok(())
}
hir::Array::WithLength(arr) => {
arr.t = self.deref_tyvar(mem::take(&mut arr.t), Covariant, arr)?;
self.resolve_expr_t(&mut arr.elem)?;
self.resolve_expr_t(&mut arr.len)?;
self.resolve_expr_t(&mut arr.elem, qvars)?;
self.resolve_expr_t(&mut arr.len, qvars)?;
Ok(())
}
other => feature_error!(
@ -823,7 +837,7 @@ impl Context {
hir::Tuple::Normal(tup) => {
tup.t = self.deref_tyvar(mem::take(&mut tup.t), Covariant, tup)?;
for elem in tup.elems.pos_args.iter_mut() {
self.resolve_expr_t(&mut elem.expr)?;
self.resolve_expr_t(&mut elem.expr, qvars)?;
}
Ok(())
}
@ -832,14 +846,14 @@ impl Context {
hir::Set::Normal(st) => {
st.t = self.deref_tyvar(mem::take(&mut st.t), Covariant, st)?;
for elem in st.elems.pos_args.iter_mut() {
self.resolve_expr_t(&mut elem.expr)?;
self.resolve_expr_t(&mut elem.expr, qvars)?;
}
Ok(())
}
hir::Set::WithLength(st) => {
st.t = self.deref_tyvar(mem::take(&mut st.t), Covariant, st)?;
self.resolve_expr_t(&mut st.elem)?;
self.resolve_expr_t(&mut st.len)?;
self.resolve_expr_t(&mut st.elem, qvars)?;
self.resolve_expr_t(&mut st.len, qvars)?;
Ok(())
}
},
@ -847,8 +861,8 @@ impl Context {
hir::Dict::Normal(dic) => {
dic.t = self.deref_tyvar(mem::take(&mut dic.t), Covariant, dic)?;
for kv in dic.kvs.iter_mut() {
self.resolve_expr_t(&mut kv.key)?;
self.resolve_expr_t(&mut kv.value)?;
self.resolve_expr_t(&mut kv.key, qvars)?;
self.resolve_expr_t(&mut kv.value, qvars)?;
}
Ok(())
}
@ -874,7 +888,7 @@ impl Context {
}
}
for chunk in attr.body.block.iter_mut() {
self.resolve_expr_t(chunk)?;
self.resolve_expr_t(chunk, qvars)?;
}
}
Ok(())
@ -882,14 +896,14 @@ impl Context {
hir::Expr::BinOp(binop) => {
let t = mem::take(binop.signature_mut_t().unwrap());
*binop.signature_mut_t().unwrap() = self.deref_tyvar(t, Covariant, binop)?;
self.resolve_expr_t(&mut binop.lhs)?;
self.resolve_expr_t(&mut binop.rhs)?;
self.resolve_expr_t(&mut binop.lhs, qvars)?;
self.resolve_expr_t(&mut binop.rhs, qvars)?;
Ok(())
}
hir::Expr::UnaryOp(unaryop) => {
let t = mem::take(unaryop.signature_mut_t().unwrap());
*unaryop.signature_mut_t().unwrap() = self.deref_tyvar(t, Covariant, unaryop)?;
self.resolve_expr_t(&mut unaryop.expr)?;
self.resolve_expr_t(&mut unaryop.expr, qvars)?;
Ok(())
}
hir::Expr::Call(call) => {
@ -897,66 +911,78 @@ impl Context {
let t = mem::take(t);
*call.signature_mut_t().unwrap() = self.deref_tyvar(t, Covariant, call)?;
}
self.resolve_expr_t(&mut call.obj)?;
self.resolve_expr_t(&mut call.obj, qvars)?;
for arg in call.args.pos_args.iter_mut() {
self.resolve_expr_t(&mut arg.expr)?;
self.resolve_expr_t(&mut arg.expr, qvars)?;
}
if let Some(var_args) = &mut call.args.var_args {
self.resolve_expr_t(&mut var_args.expr)?;
self.resolve_expr_t(&mut var_args.expr, qvars)?;
}
for arg in call.args.kw_args.iter_mut() {
self.resolve_expr_t(&mut arg.expr)?;
self.resolve_expr_t(&mut arg.expr, qvars)?;
}
Ok(())
}
hir::Expr::Def(def) => {
*def.sig.ref_mut_t() =
self.deref_tyvar(mem::take(def.sig.ref_mut_t()), Covariant, &def.sig)?;
let subr_qvars_ = def.sig.ref_t().qvars();
let subr_qvars = subr_qvars_.clone().into_iter().map(|(name, _)| name);
qvars.extend(subr_qvars);
if let Some(params) = def.sig.params_mut() {
self.resolve_params_t(params)?;
self.resolve_params_t(params, qvars)?;
}
for chunk in def.body.block.iter_mut() {
self.resolve_expr_t(chunk)?;
self.resolve_expr_t(chunk, qvars)?;
}
for (name, _) in subr_qvars_.into_iter() {
qvars.remove(&name);
}
Ok(())
}
hir::Expr::Lambda(lambda) => {
lambda.t = self.deref_tyvar(mem::take(&mut lambda.t), Covariant, lambda)?;
self.resolve_params_t(&mut lambda.params)?;
let subr_qvars_ = lambda.ref_t().qvars();
let subr_qvars = subr_qvars_.clone().into_iter().map(|(name, _)| name);
qvars.extend(subr_qvars);
self.resolve_params_t(&mut lambda.params, qvars)?;
for chunk in lambda.body.iter_mut() {
self.resolve_expr_t(chunk)?;
self.resolve_expr_t(chunk, qvars)?;
}
for (name, _) in subr_qvars_.into_iter() {
qvars.remove(&name);
}
Ok(())
}
hir::Expr::ClassDef(class_def) => {
for def in class_def.methods.iter_mut() {
self.resolve_expr_t(def)?;
self.resolve_expr_t(def, qvars)?;
}
Ok(())
}
hir::Expr::PatchDef(patch_def) => {
for def in patch_def.methods.iter_mut() {
self.resolve_expr_t(def)?;
self.resolve_expr_t(def, qvars)?;
}
Ok(())
}
hir::Expr::ReDef(redef) => {
// REVIEW: redef.attr is not dereferenced
for chunk in redef.block.iter_mut() {
self.resolve_expr_t(chunk)?;
self.resolve_expr_t(chunk, qvars)?;
}
Ok(())
}
hir::Expr::TypeAsc(tasc) => self.resolve_expr_t(&mut tasc.expr),
hir::Expr::TypeAsc(tasc) => self.resolve_expr_t(&mut tasc.expr, qvars),
hir::Expr::Code(chunks) | hir::Expr::Compound(chunks) => {
for chunk in chunks.iter_mut() {
self.resolve_expr_t(chunk)?;
self.resolve_expr_t(chunk, qvars)?;
}
Ok(())
}
hir::Expr::Dummy(chunks) => {
for chunk in chunks.iter_mut() {
self.resolve_expr_t(chunk)?;
self.resolve_expr_t(chunk, qvars)?;
}
Ok(())
}