fix: warn unused type variables

This commit is contained in:
Shunsuke Shibayama 2023-08-02 15:07:31 +09:00
parent 9734028b21
commit f298db96d1
13 changed files with 307 additions and 51 deletions

View file

@ -19,7 +19,7 @@ use crate::ty::{HasType, Predicate, Type};
use crate::{type_feature_error, unreachable_error};
use Type::*;
use crate::context::Context;
use crate::context::{Context, VarInfo};
use crate::error::{TyCheckError, TyCheckErrors, TyCheckResult};
use crate::hir;
@ -36,6 +36,7 @@ pub struct TyVarCache {
pub(crate) already_appeared: Set<Str>,
pub(crate) tyvar_instances: Dict<VarName, Type>,
pub(crate) typaram_instances: Dict<VarName, TyParam>,
pub(crate) var_infos: Dict<VarName, VarInfo>,
pub(crate) structural_inner: bool,
}
@ -43,8 +44,8 @@ impl fmt::Display for TyVarCache {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"TyVarInstContext {{ tyvar_instances: {}, typaram_instances: {} }}",
self.tyvar_instances, self.typaram_instances,
"TyVarContext {{ tyvar_instances: {}, typaram_instances: {}, var_infos: {} }}",
self.tyvar_instances, self.typaram_instances, self.var_infos
)
}
}
@ -56,6 +57,7 @@ impl TyVarCache {
already_appeared: Set::new(),
tyvar_instances: Dict::new(),
typaram_instances: Dict::new(),
var_infos: Dict::new(),
structural_inner: false,
}
}
@ -90,6 +92,25 @@ impl TyVarCache {
}
}
/// Warn when a type does not need to be a type variable, such as `|T| T -> Int` (it should be `Obj -> Int`).
///
/// TODO: This warning is currently disabled because it raises a false warning in cases like `|T|(x: T) -> (y: T) -> (x, y)`.
pub fn warn_isolated_vars(&self, ctx: &Context) {
for (name, vi) in self.var_infos.iter() {
let refs = &ctx.index().get_refs(&vi.def_loc).unwrap().referrers;
if refs.len() == 1 {
let warn = TyCheckError::unnecessary_tyvar_warning(
ctx.cfg.input.clone(),
line!() as usize,
vi.def_loc.loc,
name.inspect(),
ctx.caused_by(),
);
ctx.shared().warns.push(warn);
}
}
}
fn instantiate_constraint(
&mut self,
constr: Constraint,
@ -134,6 +155,25 @@ impl TyVarCache {
}
pub(crate) fn push_or_init_tyvar(&mut self, name: &VarName, tv: &Type, ctx: &Context) {
if let Some(inst) = self.tyvar_instances.get(name) {
self.update_tyvar(inst, tv, ctx);
} else if let Some(inst) = self.typaram_instances.get(name) {
if let Ok(inst) = <&Type>::try_from(inst) {
self.update_tyvar(inst, tv, ctx);
} else if let TyParam::FreeVar(_fv) = inst {
inst.link(&TyParam::t(tv.clone()));
} else {
unreachable!()
}
} else {
self.tyvar_instances.insert(name.clone(), tv.clone());
let vi = VarInfo::type_var(Type::Type, ctx.absolutize(name.loc()), ctx.name.clone());
ctx.index().register(name.inspect().clone(), &vi);
self.var_infos.insert(name.clone(), vi);
}
}
pub(crate) fn dummy_push_or_init_tyvar(&mut self, name: &VarName, tv: &Type, ctx: &Context) {
if let Some(inst) = self.tyvar_instances.get(name) {
self.update_tyvar(inst, tv, ctx);
} else if let Some(inst) = self.typaram_instances.get(name) {
@ -176,6 +216,30 @@ impl TyVarCache {
}
pub(crate) fn push_or_init_typaram(&mut self, name: &VarName, tp: &TyParam, ctx: &Context) {
// FIXME:
if let Some(inst) = self.typaram_instances.get(name) {
self.update_typaram(inst, tp, ctx);
} else if let Some(inst) = self.tyvar_instances.get(name) {
if let Ok(tv) = <&Type>::try_from(tp) {
self.update_tyvar(inst, tv, ctx);
} else {
unreachable!()
}
} else {
let t = ctx.get_tp_t(tp).unwrap_or(Type::Obj);
let vi = VarInfo::type_var(t, ctx.absolutize(name.loc()), ctx.name.clone());
ctx.index().register(name.inspect().clone(), &vi);
self.var_infos.insert(name.clone(), vi);
self.typaram_instances.insert(name.clone(), tp.clone());
}
}
pub(crate) fn dummy_push_or_init_typaram(
&mut self,
name: &VarName,
tp: &TyParam,
ctx: &Context,
) {
// FIXME:
if let Some(inst) = self.typaram_instances.get(name) {
self.update_typaram(inst, tp, ctx);
@ -270,7 +334,7 @@ impl Context {
if tmp_tv_cache.appeared(&name) {
let tp =
TyParam::named_free_var(name.clone(), self.level, Constraint::Uninited);
tmp_tv_cache.push_or_init_typaram(&varname, &tp, self);
tmp_tv_cache.dummy_push_or_init_typaram(&varname, &tp, self);
return Ok(tp);
}
if let Some(tv_cache) = &self.tv_cache {
@ -283,7 +347,7 @@ impl Context {
tmp_tv_cache.push_appeared(name.clone());
let constr = tmp_tv_cache.instantiate_constraint(constr, self, loc)?;
let tp = TyParam::named_free_var(name.clone(), self.level, constr);
tmp_tv_cache.push_or_init_typaram(&varname, &tp, self);
tmp_tv_cache.dummy_push_or_init_typaram(&varname, &tp, self);
Ok(tp)
}
}
@ -426,7 +490,7 @@ impl Context {
let varname = VarName::from_str(name.clone());
if tmp_tv_cache.appeared(&name) {
let tyvar = named_free_var(name.clone(), self.level, Constraint::Uninited);
tmp_tv_cache.push_or_init_tyvar(&varname, &tyvar, self);
tmp_tv_cache.dummy_push_or_init_tyvar(&varname, &tyvar, self);
return Ok(tyvar);
}
if let Some(tv_ctx) = &self.tv_cache {
@ -447,7 +511,7 @@ impl Context {
tmp_tv_cache.push_appeared(name.clone());
let constr = tmp_tv_cache.instantiate_constraint(constr, self, loc)?;
let tyvar = named_free_var(name.clone(), self.level, constr);
tmp_tv_cache.push_or_init_tyvar(&varname, &tyvar, self);
tmp_tv_cache.dummy_push_or_init_tyvar(&varname, &tyvar, self);
Ok(tyvar)
}
}