mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-02 21:44:34 +00:00
fix: ignored match arms
This commit is contained in:
parent
8e9458e75a
commit
7e48a2f9c8
10 changed files with 633 additions and 138 deletions
|
@ -18,7 +18,7 @@ use crate::ty::{HasType, Predicate, SubrType, Type};
|
|||
|
||||
use crate::context::{Context, Variance};
|
||||
use crate::error::{TyCheckError, TyCheckErrors, TyCheckResult};
|
||||
use crate::{feature_error, hir, unreachable_error};
|
||||
use crate::{feature_error, hir, mono_type_pattern, mono_value_pattern, unreachable_error};
|
||||
|
||||
use Type::*;
|
||||
use Variance::*;
|
||||
|
@ -45,7 +45,10 @@ impl Generalizer {
|
|||
fn generalize_tp(&mut self, free: TyParam, uninit: bool) -> TyParam {
|
||||
match free {
|
||||
TyParam::Type(t) => TyParam::t(self.generalize_t(*t, uninit)),
|
||||
TyParam::Value(val) => TyParam::Value(val.map_t(&mut |t| self.generalize_t(t, uninit))),
|
||||
TyParam::Value(val) => TyParam::Value(
|
||||
val.map_t(&mut |t| self.generalize_t(t, uninit))
|
||||
.map_tp(&mut |tp| self.generalize_tp(tp, uninit)),
|
||||
),
|
||||
TyParam::FreeVar(fv) if fv.is_generalized() => TyParam::FreeVar(fv),
|
||||
TyParam::FreeVar(fv) if fv.is_linked() => {
|
||||
let tp = fv.crack().clone();
|
||||
|
@ -63,6 +66,9 @@ impl Generalizer {
|
|||
.map(|tp| self.generalize_tp(tp, uninit))
|
||||
.collect(),
|
||||
),
|
||||
TyParam::UnsizedList(tp) => {
|
||||
TyParam::UnsizedList(Box::new(self.generalize_tp(*tp, uninit)))
|
||||
}
|
||||
TyParam::Tuple(tps) => TyParam::Tuple(
|
||||
tps.into_iter()
|
||||
.map(|tp| self.generalize_tp(tp, uninit))
|
||||
|
@ -126,6 +132,14 @@ impl Generalizer {
|
|||
let obj = self.generalize_tp(*obj, uninit);
|
||||
TyParam::proj(obj, attr)
|
||||
}
|
||||
TyParam::ProjCall { obj, attr, args } => {
|
||||
let obj = self.generalize_tp(*obj, uninit);
|
||||
let args = args
|
||||
.into_iter()
|
||||
.map(|tp| self.generalize_tp(tp, uninit))
|
||||
.collect();
|
||||
TyParam::proj_call(obj, attr, args)
|
||||
}
|
||||
TyParam::Erased(t) => TyParam::erased(self.generalize_t(*t, uninit)),
|
||||
TyParam::App { name, args } => {
|
||||
let args = args
|
||||
|
@ -143,13 +157,7 @@ impl Generalizer {
|
|||
let val = self.generalize_tp(*val, uninit);
|
||||
TyParam::unary(op, val)
|
||||
}
|
||||
other if other.has_no_unbound_var() => other,
|
||||
other => {
|
||||
if DEBUG_MODE {
|
||||
todo!("{other:?}");
|
||||
}
|
||||
other
|
||||
}
|
||||
TyParam::Mono(_) | TyParam::Failure => free,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,6 +209,7 @@ impl Generalizer {
|
|||
Type::FreeVar(fv)
|
||||
}
|
||||
}
|
||||
FreeVar(_) => free_type,
|
||||
Subr(mut subr) => {
|
||||
self.variance = Contravariant;
|
||||
let qnames = subr.essential_qnames();
|
||||
|
@ -229,6 +238,10 @@ impl Generalizer {
|
|||
return_t,
|
||||
)
|
||||
}
|
||||
Quantified(quant) => {
|
||||
log!(err "{quant}");
|
||||
quant.quantify()
|
||||
}
|
||||
Record(rec) => {
|
||||
let fields = rec
|
||||
.into_iter()
|
||||
|
@ -305,8 +318,14 @@ impl Generalizer {
|
|||
let to = self.generalize_t(*grd.to, uninit);
|
||||
guard(grd.namespace, grd.target, to)
|
||||
}
|
||||
// REVIEW: その他何でもそのまま通していいのか?
|
||||
other => other,
|
||||
Bounded { sub, sup } => {
|
||||
let sub = self.generalize_t(*sub, uninit);
|
||||
let sup = self.generalize_t(*sup, uninit);
|
||||
bounded(sub, sup)
|
||||
}
|
||||
Int | Nat | Float | Ratio | Complex | Bool | Str | Never | Obj | Type | Error
|
||||
| Code | Frame | NoneType | Inf | NegInf | NotImplementedType | Ellipsis
|
||||
| ClassType | TraitType | Patch | Failure | Uninited | Mono(_) => free_type,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -450,7 +469,7 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
|
|||
fn deref_value(&mut self, val: ValueObj) -> TyCheckResult<ValueObj> {
|
||||
match val {
|
||||
ValueObj::Type(mut t) => {
|
||||
t.try_map_t(|t| self.deref_tyvar(t.clone()))?;
|
||||
t.try_map_t(&mut |t| self.deref_tyvar(t.clone()))?;
|
||||
Ok(ValueObj::Type(t))
|
||||
}
|
||||
ValueObj::List(vs) => {
|
||||
|
@ -501,7 +520,8 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
|
|||
})
|
||||
}
|
||||
ValueObj::UnsizedList(v) => Ok(ValueObj::UnsizedList(Box::new(self.deref_value(*v)?))),
|
||||
_ => Ok(val),
|
||||
ValueObj::Subr(subr) => Ok(ValueObj::Subr(subr)),
|
||||
mono_value_pattern!() => Ok(val),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -526,6 +546,7 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
|
|||
fv.update_type(t);
|
||||
Ok(TyParam::FreeVar(fv))
|
||||
}
|
||||
TyParam::FreeVar(_) => Ok(tp),
|
||||
TyParam::Type(t) => Ok(TyParam::t(self.deref_tyvar(*t)?)),
|
||||
TyParam::Value(val) => self.deref_value(val).map(TyParam::Value),
|
||||
TyParam::Erased(t) => Ok(TyParam::erased(self.deref_tyvar(*t)?)),
|
||||
|
@ -558,6 +579,7 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
|
|||
}
|
||||
Ok(TyParam::List(new_tps))
|
||||
}
|
||||
TyParam::UnsizedList(tp) => Ok(TyParam::UnsizedList(Box::new(self.deref_tp(*tp)?))),
|
||||
TyParam::Tuple(tps) => {
|
||||
let mut new_tps = vec![];
|
||||
for tp in tps {
|
||||
|
@ -609,20 +631,20 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
|
|||
let nd_params = lambda
|
||||
.nd_params
|
||||
.into_iter()
|
||||
.map(|pt| pt.try_map_type(|t| self.deref_tyvar(t)))
|
||||
.map(|pt| pt.try_map_type(&mut |t| self.deref_tyvar(t)))
|
||||
.collect::<TyCheckResult<_>>()?;
|
||||
let var_params = lambda
|
||||
.var_params
|
||||
.map(|pt| pt.try_map_type(|t| self.deref_tyvar(t)))
|
||||
.map(|pt| pt.try_map_type(&mut |t| self.deref_tyvar(t)))
|
||||
.transpose()?;
|
||||
let d_params = lambda
|
||||
.d_params
|
||||
.into_iter()
|
||||
.map(|pt| pt.try_map_type(|t| self.deref_tyvar(t)))
|
||||
.map(|pt| pt.try_map_type(&mut |t| self.deref_tyvar(t)))
|
||||
.collect::<TyCheckResult<_>>()?;
|
||||
let kw_var_params = lambda
|
||||
.kw_var_params
|
||||
.map(|pt| pt.try_map_type(|t| self.deref_tyvar(t)))
|
||||
.map(|pt| pt.try_map_type(&mut |t| self.deref_tyvar(t)))
|
||||
.transpose()?;
|
||||
let body = lambda
|
||||
.body
|
||||
|
@ -645,10 +667,22 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
|
|||
attr,
|
||||
})
|
||||
}
|
||||
TyParam::ProjCall { obj, attr, args } => {
|
||||
let obj = self.deref_tp(*obj)?;
|
||||
let mut new_args = vec![];
|
||||
for arg in args.into_iter() {
|
||||
new_args.push(self.deref_tp(arg)?);
|
||||
}
|
||||
Ok(TyParam::ProjCall {
|
||||
obj: Box::new(obj),
|
||||
attr,
|
||||
args: new_args,
|
||||
})
|
||||
}
|
||||
TyParam::Failure if self.level == 0 => Err(TyCheckErrors::from(
|
||||
TyCheckError::dummy_infer_error(self.ctx.cfg.input.clone(), fn_name!(), line!()),
|
||||
)),
|
||||
t => Ok(t),
|
||||
TyParam::Mono(_) | TyParam::Failure => Ok(tp),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -765,8 +799,12 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
|
|||
let pred = self.deref_pred(*pred)?;
|
||||
Ok(!pred)
|
||||
}
|
||||
Predicate::Attr { receiver, name } => {
|
||||
let receiver = self.deref_tp(receiver)?;
|
||||
Ok(Predicate::attr(receiver, name))
|
||||
}
|
||||
Predicate::Value(v) => self.deref_value(v).map(Predicate::Value),
|
||||
_ => Ok(pred),
|
||||
Predicate::Const(_) | Predicate::Failure => Ok(pred),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -891,6 +929,7 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
|
|||
Ok(Type::FreeVar(fv))
|
||||
}
|
||||
}
|
||||
FreeVar(_) => Ok(t),
|
||||
Poly { name, mut params } => {
|
||||
let typ = poly(&name, params.clone());
|
||||
let ctx = self.ctx.get_nominal_type_ctx(&typ).ok_or_else(|| {
|
||||
|
@ -1055,7 +1094,12 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
|
|||
let to = self.deref_tyvar(*grd.to)?;
|
||||
Ok(guard(grd.namespace, grd.target, to))
|
||||
}
|
||||
t => Ok(t),
|
||||
Bounded { sub, sup } => {
|
||||
let sub = self.deref_tyvar(*sub)?;
|
||||
let sup = self.deref_tyvar(*sup)?;
|
||||
Ok(bounded(sub, sup))
|
||||
}
|
||||
mono_type_pattern!() => Ok(t),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ use crate::ty::ConstSubr;
|
|||
use crate::ty::GuardType;
|
||||
use crate::ty::ValueObj;
|
||||
use crate::ty::{HasType, Predicate, Type};
|
||||
use crate::{type_feature_error, unreachable_error};
|
||||
use crate::{mono_type_pattern, unreachable_error};
|
||||
use Type::*;
|
||||
|
||||
use crate::context::{Context, VarInfo};
|
||||
|
@ -40,7 +40,6 @@ pub struct TyVarCache {
|
|||
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,
|
||||
}
|
||||
|
||||
impl fmt::Display for TyVarCache {
|
||||
|
@ -61,7 +60,6 @@ impl TyVarCache {
|
|||
tyvar_instances: Dict::new(),
|
||||
typaram_instances: Dict::new(),
|
||||
var_infos: Dict::new(),
|
||||
structural_inner: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -419,6 +417,8 @@ impl Context {
|
|||
tmp_tv_cache.instantiate_constraint(constr, self, loc)?;
|
||||
fv.update_constraint(new_constr, true);
|
||||
}
|
||||
} else {
|
||||
todo!("{tp}");
|
||||
}
|
||||
Ok(tp)
|
||||
} else if let Some(t) = tmp_tv_cache.get_tyvar(&name) {
|
||||
|
@ -433,6 +433,8 @@ impl Context {
|
|||
tmp_tv_cache.instantiate_constraint(constr, self, loc)?;
|
||||
fv.update_constraint(new_constr, true);
|
||||
}
|
||||
} else {
|
||||
todo!("{t}");
|
||||
}
|
||||
Ok(TyParam::t(t))
|
||||
} else {
|
||||
|
@ -517,20 +519,28 @@ impl Context {
|
|||
let nd_params = lambda
|
||||
.nd_params
|
||||
.into_iter()
|
||||
.map(|pt| pt.try_map_type(|t| self.instantiate_t_inner(t, tmp_tv_cache, loc)))
|
||||
.map(|pt| {
|
||||
pt.try_map_type(&mut |t| self.instantiate_t_inner(t, tmp_tv_cache, loc))
|
||||
})
|
||||
.collect::<TyCheckResult<_>>()?;
|
||||
let var_params = lambda
|
||||
.var_params
|
||||
.map(|pt| pt.try_map_type(|t| self.instantiate_t_inner(t, tmp_tv_cache, loc)))
|
||||
.map(|pt| {
|
||||
pt.try_map_type(&mut |t| self.instantiate_t_inner(t, tmp_tv_cache, loc))
|
||||
})
|
||||
.transpose()?;
|
||||
let d_params = lambda
|
||||
.d_params
|
||||
.into_iter()
|
||||
.map(|pt| pt.try_map_type(|t| self.instantiate_t_inner(t, tmp_tv_cache, loc)))
|
||||
.map(|pt| {
|
||||
pt.try_map_type(&mut |t| self.instantiate_t_inner(t, tmp_tv_cache, loc))
|
||||
})
|
||||
.collect::<TyCheckResult<_>>()?;
|
||||
let kw_var_params = lambda
|
||||
.kw_var_params
|
||||
.map(|pt| pt.try_map_type(|t| self.instantiate_t_inner(t, tmp_tv_cache, loc)))
|
||||
.map(|pt| {
|
||||
pt.try_map_type(&mut |t| self.instantiate_t_inner(t, tmp_tv_cache, loc))
|
||||
})
|
||||
.transpose()?;
|
||||
let body = lambda
|
||||
.body
|
||||
|
@ -579,21 +589,17 @@ impl Context {
|
|||
Ok(TyParam::t(t))
|
||||
}
|
||||
TyParam::Value(val) => {
|
||||
// println!("592: {val} / {tmp_tv_cache}");
|
||||
let val = val.try_map_t(&mut |t| self.instantiate_t_inner(t, tmp_tv_cache, loc))?;
|
||||
// .try_map_tp(&mut |tp| self.instantiate_tp(tp, tmp_tv_cache, loc))?;
|
||||
// println!("596: {val} / {tmp_tv_cache}");
|
||||
Ok(TyParam::Value(val))
|
||||
}
|
||||
TyParam::Erased(t) => {
|
||||
let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?;
|
||||
Ok(TyParam::Erased(Box::new(t)))
|
||||
}
|
||||
p @ (TyParam::Mono(_) | TyParam::FreeVar(_)) => Ok(p),
|
||||
other => {
|
||||
type_feature_error!(
|
||||
self,
|
||||
loc.loc(),
|
||||
&format!("instantiating type-parameter {other}")
|
||||
)
|
||||
}
|
||||
p @ (TyParam::Mono(_) | TyParam::FreeVar(_) | TyParam::Failure) => Ok(p),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -670,7 +676,11 @@ impl Context {
|
|||
let rhs = self.instantiate_pred(*rhs, tmp_tv_cache, loc)?;
|
||||
Ok(Predicate::general_ne(lhs, rhs))
|
||||
}
|
||||
_ => Ok(pred),
|
||||
Predicate::Attr { receiver, name } => {
|
||||
let receiver = self.instantiate_tp(receiver, tmp_tv_cache, loc)?;
|
||||
Ok(Predicate::attr(receiver, name))
|
||||
}
|
||||
Predicate::Const(_) | Predicate::Failure => Ok(pred),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -714,6 +724,10 @@ impl Context {
|
|||
}
|
||||
Ok(ValueObj::List(new.into()))
|
||||
}
|
||||
ValueObj::UnsizedList(lis) => {
|
||||
let lis = self.instantiate_value(*lis, tmp_tv_cache, loc)?;
|
||||
Ok(ValueObj::UnsizedList(Box::new(lis)))
|
||||
}
|
||||
ValueObj::Tuple(tup) => {
|
||||
let mut new = vec![];
|
||||
for v in tup.iter().cloned() {
|
||||
|
@ -754,7 +768,18 @@ impl Context {
|
|||
}
|
||||
Ok(ValueObj::DataClass { name, fields: new })
|
||||
}
|
||||
_ => Ok(value),
|
||||
ValueObj::Int(_)
|
||||
| ValueObj::Nat(_)
|
||||
| ValueObj::Float(_)
|
||||
| ValueObj::Str(_)
|
||||
| ValueObj::Bool(_)
|
||||
| ValueObj::Code(_)
|
||||
| ValueObj::None
|
||||
| ValueObj::Ellipsis
|
||||
| ValueObj::Inf
|
||||
| ValueObj::NegInf
|
||||
| ValueObj::NotImplemented
|
||||
| ValueObj::Failure => Ok(value),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -776,8 +801,7 @@ impl Context {
|
|||
let t = t.clone();
|
||||
Ok(t)
|
||||
} else if let Some(tp) = tmp_tv_cache.get_typaram(&name) {
|
||||
if let TyParam::Type(t) = tp {
|
||||
let t = *t.clone();
|
||||
if let Ok(t) = self.convert_tp_into_type(tp.clone()) {
|
||||
Ok(t)
|
||||
} else {
|
||||
todo!(
|
||||
|
@ -797,8 +821,8 @@ impl Context {
|
|||
if let Some(t) = tv_ctx.get_tyvar(&name) {
|
||||
return Ok(t.clone());
|
||||
} else if let Some(tp) = tv_ctx.get_typaram(&name) {
|
||||
if let TyParam::Type(t) = tp {
|
||||
return Ok(*t.clone());
|
||||
if let Ok(t) = self.convert_tp_into_type(tp.clone()) {
|
||||
return Ok(t);
|
||||
} else {
|
||||
todo!(
|
||||
"typaram_insts: {}\ntyvar_insts:{}\n{tp}",
|
||||
|
@ -902,17 +926,9 @@ impl Context {
|
|||
Ok(poly(name, params))
|
||||
}
|
||||
Structural(t) => {
|
||||
// avoid infinite recursion
|
||||
if tmp_tv_cache.structural_inner {
|
||||
Ok(t.structuralize())
|
||||
} else {
|
||||
if t.is_recursive() {
|
||||
tmp_tv_cache.structural_inner = true;
|
||||
}
|
||||
let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?;
|
||||
Ok(t.structuralize())
|
||||
}
|
||||
}
|
||||
FreeVar(fv) => {
|
||||
if let Some((sub, sup)) = fv.get_subsup() {
|
||||
let sub = if sub.is_recursive() {
|
||||
|
@ -961,8 +977,15 @@ impl Context {
|
|||
let sup = self.instantiate_t_inner(*sup, tmp_tv_cache, loc)?;
|
||||
Ok(bounded(sub, sup))
|
||||
}
|
||||
other if other.is_monomorphic() => Ok(other),
|
||||
other => type_feature_error!(self, loc.loc(), &format!("instantiating type {other}")),
|
||||
Callable { param_ts, return_t } => {
|
||||
let param_ts = param_ts
|
||||
.into_iter()
|
||||
.map(|t| self.instantiate_t_inner(t, tmp_tv_cache, loc))
|
||||
.collect::<TyCheckResult<_>>()?;
|
||||
let return_t = self.instantiate_t_inner(*return_t, tmp_tv_cache, loc)?;
|
||||
Ok(callable(param_ts, return_t))
|
||||
}
|
||||
mono_type_pattern!() => Ok(unbound),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -983,9 +1006,9 @@ impl Context {
|
|||
if let Some(self_t) = ty.self_t() {
|
||||
self.sub_unify(callee.ref_t(), self_t, callee, Some(&Str::ever("self")))?;
|
||||
}
|
||||
if cfg!(feature = "debug") && ty.has_qvar() {
|
||||
/*if DEBUG_MODE && ty.has_qvar() {
|
||||
panic!("{ty} has qvar")
|
||||
}
|
||||
}*/
|
||||
Ok(ty)
|
||||
}
|
||||
// HACK: {op: |T|(T -> T) | op == F} => ?T -> ?T
|
||||
|
@ -1028,6 +1051,7 @@ impl Context {
|
|||
log!(err "{subr} has qvar");
|
||||
self.instantiate(Type::Subr(subr).quantify(), callee)
|
||||
}
|
||||
// There are no quantified types inside normal types (rank-0 types) due to the rank-1 restriction
|
||||
// rank-1制限により、通常の型(rank-0型)の内側に量化型は存在しない
|
||||
other => Ok(other),
|
||||
}
|
||||
|
@ -1047,9 +1071,9 @@ impl Context {
|
|||
Quantified(quant) => {
|
||||
let mut tmp_tv_cache = TyVarCache::new(self.level, self);
|
||||
let ty = self.instantiate_t_inner(*quant, &mut tmp_tv_cache, &())?;
|
||||
if cfg!(feature = "debug") && ty.has_qvar() {
|
||||
/*if DEBUG_MODE && ty.has_qvar() {
|
||||
panic!("{ty} has qvar")
|
||||
}
|
||||
}*/
|
||||
Ok(ty)
|
||||
}
|
||||
Refinement(refine) if refine.t.is_quantified_subr() => {
|
||||
|
|
|
@ -1293,21 +1293,25 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
|
|||
}
|
||||
}
|
||||
}
|
||||
(FreeVar(sub_fv), Structural(sup)) if sub_fv.is_unbound() => {
|
||||
if sub_fv.get_sub().is_none() {
|
||||
(FreeVar(sub_fv), Structural(struct_sup)) if sub_fv.is_unbound() => {
|
||||
let Some((sub, sup)) = sub_fv.get_subsup() else {
|
||||
log!(err "{sub_fv} is not a type variable");
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let sub_fields = self.ctx.fields(maybe_sub);
|
||||
for (sup_field, sup_ty) in self.ctx.fields(sup) {
|
||||
for (sup_field, sup_ty) in self.ctx.fields(struct_sup) {
|
||||
if let Some((_, sub_ty)) = sub_fields.get_key_value(&sup_field) {
|
||||
self.sub_unify(sub_ty, &sup_ty)?;
|
||||
} else if !self.ctx.subtype_of(&sub_fv.get_sub().unwrap(), &Never) {
|
||||
} else if !self.ctx.subtype_of(&sub, &Never) {
|
||||
maybe_sub.coerce(self.undoable);
|
||||
return self.sub_unify(maybe_sub, maybe_sup);
|
||||
} else {
|
||||
// e.g. ?T / Structural({ .method = (self: ?T) -> Int })
|
||||
sub_fv.update_super(|sup| self.ctx.intersection(&sup, maybe_sup));
|
||||
let constr = Constraint::new_sandwiched(
|
||||
sub.clone(),
|
||||
self.ctx.intersection(&sup, maybe_sup),
|
||||
);
|
||||
sub_fv.update_constraint(constr, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ impl SharedCompilerResource {
|
|||
|
||||
pub fn inherit<P: Into<NormalizedPathBuf>>(&self, path: P) -> Self {
|
||||
let mut _self = self.clone();
|
||||
_self.promises.path = path.into();
|
||||
_self.promises.root = path.into();
|
||||
_self
|
||||
}
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ pub struct Progress {
|
|||
#[derive(Debug, Clone, Default)]
|
||||
pub struct SharedPromises {
|
||||
graph: SharedModuleGraph,
|
||||
pub(crate) path: NormalizedPathBuf,
|
||||
pub(crate) root: NormalizedPathBuf,
|
||||
promises: Shared<Dict<NormalizedPathBuf, Promise>>,
|
||||
}
|
||||
|
||||
|
@ -98,10 +98,10 @@ impl fmt::Display for SharedPromises {
|
|||
}
|
||||
|
||||
impl SharedPromises {
|
||||
pub fn new(graph: SharedModuleGraph, path: NormalizedPathBuf) -> Self {
|
||||
pub fn new(graph: SharedModuleGraph, root: NormalizedPathBuf) -> Self {
|
||||
Self {
|
||||
graph,
|
||||
path,
|
||||
root,
|
||||
promises: Shared::new(Dict::new()),
|
||||
}
|
||||
}
|
||||
|
@ -153,25 +153,28 @@ impl SharedPromises {
|
|||
}
|
||||
|
||||
pub fn wait_until_finished(&self, path: &NormalizedPathBuf) {
|
||||
if self.promises.borrow().get(path).is_none() {
|
||||
panic!("not registered: {path}");
|
||||
}
|
||||
while !self.is_finished(path) {
|
||||
safe_yield();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(&self, path: &NormalizedPathBuf) -> std::thread::Result<()> {
|
||||
if self.graph.ancestors(path).contains(&self.path) {
|
||||
if self.graph.ancestors(path).contains(&self.root) {
|
||||
// cycle detected, `self.path` must not in the dependencies
|
||||
// Erg analysis processes never join ancestor threads (although joining ancestors itself is allowed in Rust)
|
||||
self.wait_until_finished(path);
|
||||
// self.wait_until_finished(path);
|
||||
return Ok(());
|
||||
}
|
||||
// Suppose A depends on B and C, and B depends on C.
|
||||
// In this case, B must join C before A joins C. Otherwise, a deadlock will occur.
|
||||
let children = self.graph.children(path);
|
||||
for child in children.iter() {
|
||||
if child == &self.path {
|
||||
if child == &self.root {
|
||||
continue;
|
||||
} else if self.graph.depends_on(&self.path, child) {
|
||||
} else if self.graph.depends_on(&self.root, child) {
|
||||
self.wait_until_finished(path);
|
||||
return Ok(());
|
||||
}
|
||||
|
|
|
@ -35,6 +35,9 @@ pub trait HasLevel {
|
|||
}
|
||||
fn lower(&self) {
|
||||
if let Some(lev) = self.level() {
|
||||
if lev == GENERIC_LEVEL {
|
||||
return;
|
||||
}
|
||||
self.set_level(lev.saturating_sub(1));
|
||||
}
|
||||
}
|
||||
|
@ -808,6 +811,10 @@ impl HasLevel for Free<Type> {
|
|||
if addr_eq!(*lev, level) {
|
||||
return;
|
||||
}
|
||||
// GENERIC_LEVEL variable cannot be lowered
|
||||
if *lev == GENERIC_LEVEL && level == GENERIC_LEVEL - 1 {
|
||||
return;
|
||||
}
|
||||
*lev = level;
|
||||
}
|
||||
_ => {}
|
||||
|
@ -1143,7 +1150,7 @@ impl<T: CanbeFree + Send + Clone> Free<T> {
|
|||
/// if `in_inst_or_gen` is true, constraint will be updated forcibly
|
||||
pub fn update_constraint(&self, new_constraint: Constraint, in_inst_or_gen: bool) {
|
||||
if new_constraint.get_type() == Some(&Type::Never) {
|
||||
panic!();
|
||||
panic!("{new_constraint}");
|
||||
}
|
||||
match &mut *self.borrow_mut() {
|
||||
FreeKind::Unbound {
|
||||
|
@ -1168,20 +1175,14 @@ impl<T: CanbeFree + Send + Clone> Free<T> {
|
|||
}
|
||||
|
||||
/// interior-mut
|
||||
pub fn update_sub<F>(&self, f: F)
|
||||
where
|
||||
F: FnOnce(Type) -> Type,
|
||||
{
|
||||
pub fn update_sub(&self, f: impl FnOnce(Type) -> Type) {
|
||||
let (sub, sup) = self.get_subsup().unwrap();
|
||||
let new_constraint = Constraint::new_sandwiched(f(sub), sup);
|
||||
self.update_constraint(new_constraint, true);
|
||||
}
|
||||
|
||||
/// interior-mut
|
||||
pub fn update_super<F>(&self, f: F)
|
||||
where
|
||||
F: FnOnce(Type) -> Type,
|
||||
{
|
||||
pub fn update_super(&self, f: impl FnOnce(Type) -> Type) {
|
||||
let (sub, sup) = self.get_subsup().unwrap();
|
||||
let new_constraint = Constraint::new_sandwiched(sub, f(sup));
|
||||
self.update_constraint(new_constraint, true);
|
||||
|
@ -1195,10 +1196,7 @@ impl<T: CanbeFree + Send + Clone> Free<T> {
|
|||
}
|
||||
|
||||
impl Free<TyParam> {
|
||||
pub fn map<F>(&self, f: F)
|
||||
where
|
||||
F: Fn(TyParam) -> TyParam,
|
||||
{
|
||||
pub fn map(&self, f: impl Fn(TyParam) -> TyParam) {
|
||||
if let Some(mut linked) = self.get_linked_refmut() {
|
||||
let mapped = f(mem::take(&mut *linked));
|
||||
*linked = mapped;
|
||||
|
|
|
@ -54,6 +54,36 @@ pub const STR_OMIT_THRESHOLD: usize = if DEBUG_MODE { 100 } else { 16 };
|
|||
pub const CONTAINER_OMIT_THRESHOLD: usize = if DEBUG_MODE { 100 } else { 8 };
|
||||
pub const DEFAULT_PARAMS_THRESHOLD: usize = if DEBUG_MODE { 100 } else { 5 };
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! mono_type_pattern {
|
||||
() => {
|
||||
$crate::ty::Type::Int
|
||||
| $crate::ty::Type::Nat
|
||||
| $crate::ty::Type::Float
|
||||
| $crate::ty::Type::Ratio
|
||||
| $crate::ty::Type::Complex
|
||||
| $crate::ty::Type::Inf
|
||||
| $crate::ty::Type::NegInf
|
||||
| $crate::ty::Type::Bool
|
||||
| $crate::ty::Type::Str
|
||||
| $crate::ty::Type::Code
|
||||
| $crate::ty::Type::Frame
|
||||
| $crate::ty::Type::Type
|
||||
| $crate::ty::Type::TraitType
|
||||
| $crate::ty::Type::ClassType
|
||||
| $crate::ty::Type::Patch
|
||||
| $crate::ty::Type::NoneType
|
||||
| $crate::ty::Type::NotImplementedType
|
||||
| $crate::ty::Type::Ellipsis
|
||||
| $crate::ty::Type::Error
|
||||
| $crate::ty::Type::Obj
|
||||
| $crate::ty::Type::Never
|
||||
| $crate::ty::Type::Failure
|
||||
| $crate::ty::Type::Mono(_)
|
||||
| $crate::ty::Type::Uninited
|
||||
};
|
||||
}
|
||||
|
||||
/// cloneのコストがあるためなるべく.ref_tを使うようにすること
|
||||
/// いくつかの構造体は直接Typeを保持していないので、その場合は.tを使う
|
||||
#[allow(unused_variables)]
|
||||
|
@ -256,10 +286,7 @@ impl ParamTy {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn try_map_type<F, E>(self, f: F) -> Result<Self, E>
|
||||
where
|
||||
F: FnOnce(Type) -> Result<Type, E>,
|
||||
{
|
||||
pub fn try_map_type<E>(self, f: &mut impl FnMut(Type) -> Result<Type, E>) -> Result<Self, E> {
|
||||
match self {
|
||||
Self::Pos(ty) => Ok(Self::Pos(f(ty)?)),
|
||||
Self::Kw { name, ty } => Ok(Self::Kw { name, ty: f(ty)? }),
|
||||
|
@ -271,6 +298,20 @@ impl ParamTy {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn try_map_default_type<E>(
|
||||
self,
|
||||
f: &mut impl FnMut(Type) -> Result<Type, E>,
|
||||
) -> Result<Self, E> {
|
||||
match self {
|
||||
Self::KwWithDefault { name, ty, default } => Ok(Self::KwWithDefault {
|
||||
name,
|
||||
ty,
|
||||
default: f(default)?,
|
||||
}),
|
||||
_ => Ok(self),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deconstruct(self) -> (Option<Str>, Type, Option<Type>) {
|
||||
match self {
|
||||
Self::Pos(ty) => (None, ty, None),
|
||||
|
@ -532,24 +573,55 @@ impl SubrType {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn map_tp(self, f: impl Fn(TyParam) -> TyParam + Copy) -> Self {
|
||||
let f = |t: Type| t.map_tp(f);
|
||||
pub fn map_tp(self, f: &mut impl FnMut(TyParam) -> TyParam) -> Self {
|
||||
let mut f_ = |t: Type| t.map_tp(f);
|
||||
Self::new(
|
||||
self.kind,
|
||||
self.non_default_params
|
||||
.into_iter()
|
||||
.map(|pt| pt.map_type(f))
|
||||
.map(|pt| pt.map_type(&mut f_))
|
||||
.collect(),
|
||||
self.var_params.map(|pt| pt.map_type(f)),
|
||||
self.var_params.map(|pt| pt.map_type(&mut f_)),
|
||||
self.default_params
|
||||
.into_iter()
|
||||
.map(|pt| pt.map_type(f).map_default_type(f))
|
||||
.map(|pt| pt.map_type(&mut f_).map_default_type(&mut f_))
|
||||
.collect(),
|
||||
self.kw_var_params.map(|pt| pt.map_type(f)),
|
||||
f(*self.return_t),
|
||||
self.kw_var_params.map(|pt| pt.map_type(&mut f_)),
|
||||
f_(*self.return_t),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn try_map_tp<E>(
|
||||
self,
|
||||
f: &mut impl FnMut(TyParam) -> Result<TyParam, E>,
|
||||
) -> Result<Self, E> {
|
||||
let mut f_ = |t: Type| t.try_map_tp(f);
|
||||
let var_params = if let Some(var_params) = self.var_params {
|
||||
Some(var_params.try_map_type(&mut f_)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let kw_var_params = if let Some(kw_var_params) = self.kw_var_params {
|
||||
Some(kw_var_params.try_map_type(&mut f_)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Ok(Self::new(
|
||||
self.kind,
|
||||
self.non_default_params
|
||||
.into_iter()
|
||||
.map(|pt| pt.try_map_type(&mut f_))
|
||||
.collect::<Result<_, _>>()?,
|
||||
var_params,
|
||||
self.default_params
|
||||
.into_iter()
|
||||
.map(|pt| pt.try_map_type(&mut f_)?.try_map_default_type(&mut f_))
|
||||
.collect::<Result<_, _>>()?,
|
||||
kw_var_params,
|
||||
self.return_t.try_map_tp(f)?,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn contains_value(&self, target: &ValueObj) -> bool {
|
||||
self.non_default_params
|
||||
.iter()
|
||||
|
@ -3334,9 +3406,13 @@ impl Type {
|
|||
}
|
||||
Type::FreeVar(fv) if fv.is_unbound_and_sandwiched() => {
|
||||
let (sub, _sup) = fv.get_subsup().unwrap();
|
||||
if self.addr_eq(&sub) {
|
||||
self.destructive_link(&Type::Never);
|
||||
} else {
|
||||
sub.destructive_coerce();
|
||||
self.destructive_link(&sub);
|
||||
}
|
||||
}
|
||||
Type::And(l, r) | Type::Or(l, r) => {
|
||||
l.destructive_coerce();
|
||||
r.destructive_coerce();
|
||||
|
@ -3349,6 +3425,32 @@ impl Type {
|
|||
}
|
||||
}
|
||||
}
|
||||
Type::Bounded { sub, sup } => {
|
||||
sub.destructive_coerce();
|
||||
sup.destructive_coerce();
|
||||
}
|
||||
Type::Ref(t) => t.destructive_coerce(),
|
||||
Type::RefMut { before, after } => {
|
||||
before.destructive_coerce();
|
||||
if let Some(after) = after {
|
||||
after.destructive_coerce();
|
||||
}
|
||||
}
|
||||
Type::Structural(ty) => ty.destructive_coerce(),
|
||||
Type::Record(r) => {
|
||||
for t in r.values() {
|
||||
t.destructive_coerce();
|
||||
}
|
||||
}
|
||||
Type::NamedTuple(r) => {
|
||||
for (_, t) in r.iter() {
|
||||
t.destructive_coerce();
|
||||
}
|
||||
}
|
||||
Type::Refinement(refine) => {
|
||||
refine.t.destructive_coerce();
|
||||
// refine.pred.destructive_coerce();
|
||||
}
|
||||
Type::Subr(subr) => subr.destructive_coerce(),
|
||||
// TODO:
|
||||
_ => {}
|
||||
|
@ -3362,9 +3464,13 @@ impl Type {
|
|||
}
|
||||
Type::FreeVar(fv) if fv.is_unbound_and_sandwiched() => {
|
||||
let (sub, _sup) = fv.get_subsup().unwrap();
|
||||
if self.addr_eq(&sub) {
|
||||
self.undoable_link(&Type::Never, list);
|
||||
} else {
|
||||
sub.undoable_coerce(list);
|
||||
self.undoable_link(&sub, list);
|
||||
}
|
||||
}
|
||||
Type::And(l, r) | Type::Or(l, r) => {
|
||||
l.undoable_coerce(list);
|
||||
r.undoable_coerce(list);
|
||||
|
@ -3831,7 +3937,7 @@ impl Type {
|
|||
// At least in situations where this function is needed, self cannot be Quantified.
|
||||
Self::Quantified(quant) => {
|
||||
if quant.return_t()?.is_generalized() {
|
||||
log!(err "quantified return type (recursive function type inference)");
|
||||
log!(err "quantified return type (recursive function type inference?)");
|
||||
}
|
||||
quant.return_t()
|
||||
}
|
||||
|
@ -4334,7 +4440,7 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
fn map_tp(self, f: impl Fn(TyParam) -> TyParam + Copy) -> Type {
|
||||
fn map_tp(self, f: &mut impl FnMut(TyParam) -> TyParam) -> Type {
|
||||
match self {
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().map_tp(f),
|
||||
Self::FreeVar(fv) => {
|
||||
|
@ -4411,6 +4517,96 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn try_map_tp<E>(
|
||||
self,
|
||||
f: &mut impl FnMut(TyParam) -> Result<TyParam, E>,
|
||||
) -> Result<Type, E> {
|
||||
match self {
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().try_map_tp(f),
|
||||
Self::FreeVar(fv) => {
|
||||
let fv_clone = fv.deep_clone();
|
||||
if let Some((sub, sup)) = fv_clone.get_subsup() {
|
||||
fv.dummy_link();
|
||||
fv_clone.dummy_link();
|
||||
let sub = sub.try_map_tp(f)?;
|
||||
let sup = sup.try_map_tp(f)?;
|
||||
fv.undo();
|
||||
fv_clone.undo();
|
||||
fv_clone.update_constraint(Constraint::new_sandwiched(sub, sup), true);
|
||||
} else if let Some(ty) = fv_clone.get_type() {
|
||||
fv_clone.update_constraint(Constraint::new_type_of(ty.try_map_tp(f)?), true);
|
||||
}
|
||||
Ok(Self::FreeVar(fv_clone))
|
||||
}
|
||||
Self::Refinement(mut refine) => {
|
||||
refine.t = Box::new(refine.t.try_map_tp(f)?);
|
||||
refine.pred = Box::new(refine.pred.try_map_tp(f)?);
|
||||
Ok(Self::Refinement(refine))
|
||||
}
|
||||
Self::Record(mut rec) => {
|
||||
for v in rec.values_mut() {
|
||||
*v = std::mem::take(v).try_map_tp(f)?;
|
||||
}
|
||||
Ok(Self::Record(rec))
|
||||
}
|
||||
Self::NamedTuple(mut r) => {
|
||||
for (_, v) in r.iter_mut() {
|
||||
*v = std::mem::take(v).try_map_tp(f)?;
|
||||
}
|
||||
Ok(Self::NamedTuple(r))
|
||||
}
|
||||
Self::Subr(subr) => Ok(Self::Subr(subr.try_map_tp(f)?)),
|
||||
Self::Callable { param_ts, return_t } => {
|
||||
let param_ts = param_ts
|
||||
.into_iter()
|
||||
.map(|t| t.try_map_tp(f))
|
||||
.collect::<Result<_, _>>()?;
|
||||
let return_t = Box::new(return_t.try_map_tp(f)?);
|
||||
Ok(Self::Callable { param_ts, return_t })
|
||||
}
|
||||
Self::Quantified(quant) => Ok(quant.try_map_tp(f)?.quantify()),
|
||||
Self::Poly { name, params } => {
|
||||
let params = params.into_iter().map(f).collect::<Result<_, _>>()?;
|
||||
Ok(Self::Poly { name, params })
|
||||
}
|
||||
Self::Ref(t) => Ok(Self::Ref(Box::new(t.try_map_tp(f)?))),
|
||||
Self::RefMut { before, after } => {
|
||||
let after = match after {
|
||||
Some(t) => Some(Box::new(t.try_map_tp(f)?)),
|
||||
None => None,
|
||||
};
|
||||
Ok(Self::RefMut {
|
||||
before: Box::new(before.try_map_tp(f)?),
|
||||
after,
|
||||
})
|
||||
}
|
||||
Self::And(l, r) => Ok(l.try_map_tp(f)? & r.try_map_tp(f)?),
|
||||
Self::Or(l, r) => Ok(l.try_map_tp(f)? | r.try_map_tp(f)?),
|
||||
Self::Not(ty) => Ok(!ty.try_map_tp(f)?),
|
||||
Self::Proj { lhs, rhs } => Ok(lhs.try_map_tp(f)?.proj(rhs)),
|
||||
Self::ProjCall {
|
||||
lhs,
|
||||
attr_name,
|
||||
args,
|
||||
} => {
|
||||
let lhs = f(*lhs)?;
|
||||
let args = args.into_iter().map(f).collect::<Result<_, _>>()?;
|
||||
Ok(proj_call(lhs, attr_name, args))
|
||||
}
|
||||
Self::Structural(ty) => Ok(ty.try_map_tp(f)?.structuralize()),
|
||||
Self::Guard(guard) => Ok(Self::Guard(GuardType::new(
|
||||
guard.namespace,
|
||||
guard.target.clone(),
|
||||
guard.to.try_map_tp(f)?,
|
||||
))),
|
||||
Self::Bounded { sub, sup } => Ok(Self::Bounded {
|
||||
sub: Box::new(sub.try_map_tp(f)?),
|
||||
sup: Box::new(sup.try_map_tp(f)?),
|
||||
}),
|
||||
mono_type_pattern!() => Ok(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn replace_param(self, target: &str, to: &str) -> Self {
|
||||
match self {
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().replace_param(target, to),
|
||||
|
@ -4540,9 +4736,9 @@ impl Type {
|
|||
return;
|
||||
}
|
||||
if self.level() == Some(GENERIC_LEVEL) {
|
||||
if DEBUG_MODE {
|
||||
/*if DEBUG_MODE {
|
||||
panic!("{self} is fixed");
|
||||
}
|
||||
}*/
|
||||
return;
|
||||
}
|
||||
let to = to.clone().eliminate_sub(self).eliminate_recursion(self);
|
||||
|
|
|
@ -929,11 +929,11 @@ impl Predicate {
|
|||
}
|
||||
|
||||
pub fn _replace_tp(self, target: &TyParam, to: &TyParam) -> Self {
|
||||
self.map_tp(|tp| tp._replace(target, to))
|
||||
self.map_tp(&mut |tp| tp._replace(target, to))
|
||||
}
|
||||
|
||||
pub fn replace_tp(self, target: &TyParam, to: &TyParam) -> Self {
|
||||
self.map_tp(|tp| tp.replace(target, to))
|
||||
self.map_tp(&mut |tp| tp.replace(target, to))
|
||||
}
|
||||
|
||||
pub fn _replace_t(self, target: &Type, to: &Type) -> Self {
|
||||
|
@ -1003,7 +1003,7 @@ impl Predicate {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn map_tp(self, f: impl Fn(TyParam) -> TyParam + Copy) -> Self {
|
||||
pub fn map_tp(self, f: &mut impl FnMut(TyParam) -> TyParam) -> Self {
|
||||
match self {
|
||||
Self::Value(val) => Self::Value(val.map_tp(f)),
|
||||
Self::Const(_) => self,
|
||||
|
@ -1058,4 +1058,56 @@ impl Predicate {
|
|||
_ => self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_map_tp<E>(
|
||||
self,
|
||||
f: &mut impl FnMut(TyParam) -> Result<TyParam, E>,
|
||||
) -> Result<Self, E> {
|
||||
match self {
|
||||
Self::Value(val) => Ok(Self::Value(val.try_map_tp(f)?)),
|
||||
Self::Call {
|
||||
receiver,
|
||||
args,
|
||||
name,
|
||||
} => Ok(Self::Call {
|
||||
receiver: f(receiver)?,
|
||||
args: args.into_iter().map(f).collect::<Result<_, E>>()?,
|
||||
name,
|
||||
}),
|
||||
Self::Attr { receiver, name } => Ok(Self::Attr {
|
||||
receiver: f(receiver)?,
|
||||
name,
|
||||
}),
|
||||
Self::Equal { lhs, rhs } => Ok(Self::Equal { lhs, rhs: f(rhs)? }),
|
||||
Self::GreaterEqual { lhs, rhs } => Ok(Self::GreaterEqual { lhs, rhs: f(rhs)? }),
|
||||
Self::LessEqual { lhs, rhs } => Ok(Self::LessEqual { lhs, rhs: f(rhs)? }),
|
||||
Self::NotEqual { lhs, rhs } => Ok(Self::NotEqual { lhs, rhs: f(rhs)? }),
|
||||
Self::GeneralEqual { lhs, rhs } => Ok(Self::GeneralEqual {
|
||||
lhs: Box::new(lhs.try_map_tp(f)?),
|
||||
rhs: Box::new(rhs.try_map_tp(f)?),
|
||||
}),
|
||||
Self::GeneralLessEqual { lhs, rhs } => Ok(Self::GeneralLessEqual {
|
||||
lhs: Box::new(lhs.try_map_tp(f)?),
|
||||
rhs: Box::new(rhs.try_map_tp(f)?),
|
||||
}),
|
||||
Self::GeneralGreaterEqual { lhs, rhs } => Ok(Self::GeneralGreaterEqual {
|
||||
lhs: Box::new(lhs.try_map_tp(f)?),
|
||||
rhs: Box::new(rhs.try_map_tp(f)?),
|
||||
}),
|
||||
Self::GeneralNotEqual { lhs, rhs } => Ok(Self::GeneralNotEqual {
|
||||
lhs: Box::new(lhs.try_map_tp(f)?),
|
||||
rhs: Box::new(rhs.try_map_tp(f)?),
|
||||
}),
|
||||
Self::And(lhs, rhs) => Ok(Self::And(
|
||||
Box::new(lhs.try_map_tp(f)?),
|
||||
Box::new(rhs.try_map_tp(f)?),
|
||||
)),
|
||||
Self::Or(lhs, rhs) => Ok(Self::Or(
|
||||
Box::new(lhs.try_map_tp(f)?),
|
||||
Box::new(rhs.try_map_tp(f)?),
|
||||
)),
|
||||
Self::Not(pred) => Ok(Self::Not(Box::new(pred.try_map_tp(f)?))),
|
||||
_ => Ok(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1531,7 +1531,7 @@ impl TyParam {
|
|||
if self.qual_name().is_some_and(|n| n == var) {
|
||||
return to.clone();
|
||||
}
|
||||
self.map(|tp| tp.substitute(var, to))
|
||||
self.map(&mut |tp| tp.substitute(var, to))
|
||||
}
|
||||
|
||||
pub fn replace(self, target: &TyParam, to: &TyParam) -> TyParam {
|
||||
|
@ -1546,7 +1546,7 @@ impl TyParam {
|
|||
match self {
|
||||
TyParam::Type(t) => TyParam::t(t._replace_tp(target, to)),
|
||||
TyParam::Value(val) => TyParam::value(val.replace_tp(target, to)),
|
||||
self_ => self_.map(|tp| tp._replace(target, to)),
|
||||
self_ => self_.map(&mut |tp| tp._replace(target, to)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1561,7 +1561,7 @@ impl TyParam {
|
|||
Self::Type(t) => Self::t(t._replace(target, to)),
|
||||
Self::Erased(t) => Self::erased(t._replace(target, to)),
|
||||
Self::Value(val) => Self::Value(val.replace_t(target, to)),
|
||||
_ => self.map(|tp| tp.replace_t(target, to)),
|
||||
_ => self.map(&mut |tp| tp.replace_t(target, to)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1592,8 +1592,11 @@ impl TyParam {
|
|||
if self.addr_eq(to) {
|
||||
return;
|
||||
}
|
||||
if DEBUG_MODE && self.level() == Some(GENERIC_LEVEL) {
|
||||
if self.level() == Some(GENERIC_LEVEL) {
|
||||
/*if DEBUG_MODE {
|
||||
panic!("{self} is fixed");
|
||||
}*/
|
||||
return;
|
||||
}
|
||||
match self {
|
||||
Self::FreeVar(fv) => fv.link(to),
|
||||
|
@ -1858,7 +1861,8 @@ impl TyParam {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn map(self, f: impl Fn(TyParam) -> TyParam + Copy) -> TyParam {
|
||||
/// For recursive function
|
||||
pub fn map(self, f: &mut impl FnMut(TyParam) -> TyParam) -> TyParam {
|
||||
match self {
|
||||
TyParam::FreeVar(fv) if fv.is_linked() => f(fv.unwrap_linked()),
|
||||
TyParam::App { name, args } => {
|
||||
|
@ -1901,15 +1905,12 @@ impl TyParam {
|
|||
obj: Box::new(f(*obj)),
|
||||
attr,
|
||||
},
|
||||
TyParam::ProjCall { obj, attr, args } => {
|
||||
let new_args = args.into_iter().map(f).collect::<Vec<_>>();
|
||||
TyParam::ProjCall {
|
||||
TyParam::ProjCall { obj, attr, args } => TyParam::ProjCall {
|
||||
obj: Box::new(f(*obj)),
|
||||
attr,
|
||||
args: new_args,
|
||||
}
|
||||
}
|
||||
TyParam::Value(val) => TyParam::Value(val.map_t(&mut |t| t.map_tp(f))),
|
||||
args: args.into_iter().map(f).collect::<Vec<_>>(),
|
||||
},
|
||||
TyParam::Value(val) => TyParam::Value(val.map_tp(f)),
|
||||
self_ => self_,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use erg_common::python_util::PythonVersion;
|
|||
use erg_common::serialize::*;
|
||||
use erg_common::set::Set;
|
||||
use erg_common::traits::LimitedDisplay;
|
||||
use erg_common::{dict, fmt_iter, impl_display_from_debug, log, switch_lang};
|
||||
use erg_common::{dict, fmt_iter, log, switch_lang};
|
||||
use erg_common::{ArcArray, Str};
|
||||
use erg_parser::ast::{ConstArgs, ConstExpr};
|
||||
|
||||
|
@ -377,12 +377,20 @@ impl GenTypeObj {
|
|||
*self.typ_mut() = f(std::mem::take(self.typ_mut()));
|
||||
}
|
||||
|
||||
pub fn map_tp(&mut self, f: impl Fn(TyParam) -> TyParam + Copy) {
|
||||
pub fn map_tp(&mut self, f: &mut impl FnMut(TyParam) -> TyParam) {
|
||||
*self.typ_mut() = std::mem::take(self.typ_mut()).map_tp(f);
|
||||
}
|
||||
|
||||
pub fn try_map_t<E>(&mut self, f: impl FnOnce(Type) -> Result<Type, E>) -> Result<(), E> {
|
||||
*self.typ_mut() = f(self.typ().clone())?;
|
||||
*self.typ_mut() = f(std::mem::take(self.typ_mut()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn try_map_tp<E>(
|
||||
&mut self,
|
||||
f: &mut impl FnMut(TyParam) -> Result<TyParam, E>,
|
||||
) -> Result<(), E> {
|
||||
*self.typ_mut() = std::mem::take(self.typ_mut()).try_map_tp(f)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -493,7 +501,7 @@ impl TypeObj {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn map_tp(&mut self, f: impl Fn(TyParam) -> TyParam + Copy) {
|
||||
pub fn map_tp(&mut self, f: &mut impl FnMut(TyParam) -> TyParam) {
|
||||
match self {
|
||||
TypeObj::Builtin { t, .. } => *t = std::mem::take(t).map_tp(f),
|
||||
TypeObj::Generated(t) => t.map_tp(f),
|
||||
|
@ -505,25 +513,49 @@ impl TypeObj {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn mapped_tp(mut self, f: impl Fn(TyParam) -> TyParam + Copy) -> Self {
|
||||
pub fn mapped_tp(mut self, f: &mut impl FnMut(TyParam) -> TyParam) -> Self {
|
||||
self.map_tp(f);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn try_map_t<E>(&mut self, f: impl FnOnce(Type) -> Result<Type, E>) -> Result<(), E> {
|
||||
pub fn try_map_t<E>(&mut self, f: &mut impl FnMut(Type) -> Result<Type, E>) -> Result<(), E> {
|
||||
match self {
|
||||
TypeObj::Builtin { t, .. } => {
|
||||
*t = f(t.clone())?;
|
||||
*t = f(std::mem::take(t))?;
|
||||
Ok(())
|
||||
}
|
||||
TypeObj::Generated(t) => t.try_map_t(f),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_mapped_t<E>(mut self, f: impl FnOnce(Type) -> Result<Type, E>) -> Result<Self, E> {
|
||||
pub fn try_mapped_t<E>(
|
||||
mut self,
|
||||
f: &mut impl FnMut(Type) -> Result<Type, E>,
|
||||
) -> Result<Self, E> {
|
||||
self.try_map_t(f)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn try_map_tp<E>(
|
||||
&mut self,
|
||||
f: &mut impl FnMut(TyParam) -> Result<TyParam, E>,
|
||||
) -> Result<(), E> {
|
||||
match self {
|
||||
TypeObj::Builtin { t, .. } => {
|
||||
*t = std::mem::take(t).try_map_tp(f)?;
|
||||
Ok(())
|
||||
}
|
||||
TypeObj::Generated(t) => t.try_map_tp(f),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_mapped_tp<E>(
|
||||
mut self,
|
||||
f: &mut impl FnMut(TyParam) -> Result<TyParam, E>,
|
||||
) -> Result<Self, E> {
|
||||
self.try_map_tp(f)?;
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// 値オブジェクト
|
||||
|
@ -558,6 +590,24 @@ pub enum ValueObj {
|
|||
Failure, // placeholder for illegal values
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! mono_value_pattern {
|
||||
() => {
|
||||
$crate::ty::ValueObj::Int(_)
|
||||
| $crate::ty::ValueObj::Nat(_)
|
||||
| $crate::ty::ValueObj::Float(_)
|
||||
| $crate::ty::ValueObj::Inf
|
||||
| $crate::ty::ValueObj::NegInf
|
||||
| $crate::ty::ValueObj::Bool(_)
|
||||
| $crate::ty::ValueObj::Str(_)
|
||||
| $crate::ty::ValueObj::Code(_)
|
||||
| $crate::ty::ValueObj::None
|
||||
| $crate::ty::ValueObj::NotImplemented
|
||||
| $crate::ty::ValueObj::Ellipsis
|
||||
| $crate::ty::ValueObj::Failure
|
||||
};
|
||||
}
|
||||
|
||||
impl fmt::Debug for ValueObj {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
|
@ -630,8 +680,8 @@ impl fmt::Debug for ValueObj {
|
|||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
Self::Subr(subr) => write!(f, "{subr}"),
|
||||
Self::Type(t) => write!(f, "{t}"),
|
||||
Self::Subr(subr) => subr.fmt(f),
|
||||
Self::Type(t) => t.fmt(f),
|
||||
Self::None => write!(f, "None"),
|
||||
Self::Ellipsis => write!(f, "Ellipsis"),
|
||||
Self::NotImplemented => write!(f, "NotImplemented"),
|
||||
|
@ -642,7 +692,89 @@ impl fmt::Debug for ValueObj {
|
|||
}
|
||||
}
|
||||
|
||||
impl_display_from_debug!(ValueObj);
|
||||
impl fmt::Display for ValueObj {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Int(i) => {
|
||||
if cfg!(feature = "debug") {
|
||||
write!(f, "Int({i})")
|
||||
} else {
|
||||
write!(f, "{i}")
|
||||
}
|
||||
}
|
||||
Self::Nat(n) => {
|
||||
if cfg!(feature = "debug") {
|
||||
write!(f, "Nat({n})")
|
||||
} else {
|
||||
write!(f, "{n}")
|
||||
}
|
||||
}
|
||||
Self::Float(fl) => {
|
||||
// In Rust, .0 is shown omitted.
|
||||
if fl.fract() < 1e-10 {
|
||||
write!(f, "{fl:.1}")?;
|
||||
} else {
|
||||
write!(f, "{fl}")?;
|
||||
}
|
||||
if cfg!(feature = "debug") {
|
||||
write!(f, "f64")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Self::Str(s) => write!(f, "\"{}\"", s.escape()),
|
||||
Self::Bool(b) => {
|
||||
if *b {
|
||||
write!(f, "True")
|
||||
} else {
|
||||
write!(f, "False")
|
||||
}
|
||||
}
|
||||
Self::List(lis) => write!(f, "[{}]", fmt_iter(lis.iter())),
|
||||
Self::UnsizedList(elem) => write!(f, "[{elem}; _]"),
|
||||
Self::Dict(dict) => {
|
||||
write!(f, "{{")?;
|
||||
for (i, (k, v)) in dict.iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "{k}: {v}")?;
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
Self::Tuple(tup) => write!(f, "({})", fmt_iter(tup.iter())),
|
||||
Self::Set(st) => write!(f, "{{{}}}", fmt_iter(st.iter())),
|
||||
Self::Code(code) => write!(f, "{code}"),
|
||||
Self::Record(rec) => {
|
||||
write!(f, "{{")?;
|
||||
for (i, (k, v)) in rec.iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(f, "; ")?;
|
||||
}
|
||||
write!(f, "{k} = {v}")?;
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
Self::DataClass { name, fields } => {
|
||||
write!(f, "{name} {{")?;
|
||||
for (i, (k, v)) in fields.iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(f, "; ")?;
|
||||
}
|
||||
write!(f, "{k} = {v}")?;
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
Self::Subr(subr) => subr.fmt(f),
|
||||
Self::Type(t) => t.fmt(f),
|
||||
Self::None => write!(f, "None"),
|
||||
Self::Ellipsis => write!(f, "Ellipsis"),
|
||||
Self::NotImplemented => write!(f, "NotImplemented"),
|
||||
Self::NegInf => write!(f, "-Inf"),
|
||||
Self::Inf => write!(f, "Inf"),
|
||||
Self::Failure => write!(f, "<failure>"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LimitedDisplay for ValueObj {
|
||||
fn limited_fmt<W: std::fmt::Write>(&self, f: &mut W, limit: isize) -> std::fmt::Result {
|
||||
|
@ -1652,7 +1784,7 @@ impl ValueObj {
|
|||
name,
|
||||
fields: fields.into_iter().map(|(k, v)| (k, v.map_t(f))).collect(),
|
||||
},
|
||||
ValueObj::UnsizedList(elem) => ValueObj::UnsizedList(Box::new(elem.clone().map_t(f))),
|
||||
ValueObj::UnsizedList(elem) => ValueObj::UnsizedList(Box::new(elem.map_t(f))),
|
||||
self_ => self_,
|
||||
}
|
||||
}
|
||||
|
@ -1692,14 +1824,12 @@ impl ValueObj {
|
|||
.map(|(k, v)| Ok((k, v.try_map_t(f)?)))
|
||||
.collect::<Result<Dict<_, _>, _>>()?,
|
||||
}),
|
||||
ValueObj::UnsizedList(elem) => {
|
||||
Ok(ValueObj::UnsizedList(Box::new(elem.clone().try_map_t(f)?)))
|
||||
}
|
||||
ValueObj::UnsizedList(elem) => Ok(ValueObj::UnsizedList(Box::new(elem.try_map_t(f)?))),
|
||||
self_ => Ok(self_),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_tp(self, f: impl Fn(TyParam) -> TyParam + Copy) -> Self {
|
||||
pub fn map_tp(self, f: &mut impl FnMut(TyParam) -> TyParam) -> Self {
|
||||
match self {
|
||||
ValueObj::Type(obj) => ValueObj::Type(obj.mapped_tp(f)),
|
||||
ValueObj::List(lis) => {
|
||||
|
@ -1721,11 +1851,54 @@ impl ValueObj {
|
|||
name,
|
||||
fields: fields.into_iter().map(|(k, v)| (k, v.map_tp(f))).collect(),
|
||||
},
|
||||
ValueObj::UnsizedList(elem) => ValueObj::UnsizedList(Box::new(elem.clone().map_tp(f))),
|
||||
ValueObj::UnsizedList(elem) => ValueObj::UnsizedList(Box::new(elem.map_tp(f))),
|
||||
self_ => self_,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_map_tp<E>(
|
||||
self,
|
||||
f: &mut impl FnMut(TyParam) -> Result<TyParam, E>,
|
||||
) -> Result<Self, E> {
|
||||
match self {
|
||||
ValueObj::Type(obj) => Ok(ValueObj::Type(obj.try_mapped_tp(f)?)),
|
||||
ValueObj::List(lis) => Ok(ValueObj::List(
|
||||
lis.iter()
|
||||
.map(|v| v.clone().try_map_tp(f))
|
||||
.collect::<Result<Arc<_>, _>>()?,
|
||||
)),
|
||||
ValueObj::Tuple(tup) => Ok(ValueObj::Tuple(
|
||||
tup.iter()
|
||||
.map(|v| v.clone().try_map_tp(f))
|
||||
.collect::<Result<Arc<_>, _>>()?,
|
||||
)),
|
||||
ValueObj::Set(st) => Ok(ValueObj::Set(
|
||||
st.into_iter()
|
||||
.map(|v| v.try_map_tp(f))
|
||||
.collect::<Result<Set<_>, _>>()?,
|
||||
)),
|
||||
ValueObj::Dict(dict) => Ok(ValueObj::Dict(
|
||||
dict.into_iter()
|
||||
.map(|(k, v)| Ok((k.try_map_tp(f)?, v.try_map_tp(f)?)))
|
||||
.collect::<Result<Dict<_, _>, _>>()?,
|
||||
)),
|
||||
ValueObj::Record(rec) => Ok(ValueObj::Record(
|
||||
rec.into_iter()
|
||||
.map(|(k, v)| Ok((k, v.try_map_tp(f)?)))
|
||||
.collect::<Result<Dict<_, _>, _>>()?,
|
||||
)),
|
||||
ValueObj::DataClass { name, fields } => Ok(ValueObj::DataClass {
|
||||
name,
|
||||
fields: fields
|
||||
.into_iter()
|
||||
.map(|(k, v)| Ok((k, v.try_map_tp(f)?)))
|
||||
.collect::<Result<Dict<_, _>, _>>()?,
|
||||
}),
|
||||
ValueObj::UnsizedList(elem) => Ok(ValueObj::UnsizedList(Box::new(elem.try_map_tp(f)?))),
|
||||
self_ => Ok(self_),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn replace_t(self, target: &Type, to: &Type) -> Self {
|
||||
self.map_t(&mut |t| t._replace(target, to))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue