fix: infinite recursion bug

This commit is contained in:
Shunsuke Shibayama 2024-08-29 22:36:23 +09:00
parent 06412bf7d2
commit 52595bde1c
5 changed files with 136 additions and 52 deletions

View file

@ -626,6 +626,7 @@ macro_rules! set_recursion_limit {
let counter = $crate::macros::RecursionCounter::new(&COUNTER);
if counter.limit_reached() {
$crate::log!(err "Recursion limit reached");
return $returns;
}
};

View file

@ -406,11 +406,17 @@ impl<'c> Substituter<'c> {
/// -> Iterable(Int)
/// ```
pub(crate) fn substitute_self(qt: &Type, subtype: &Type, ctx: &'c Context) -> Option<Self> {
#[allow(clippy::blocks_in_conditions)]
for t in qt.contained_ts() {
if t.is_qvar()
&& &t.qual_name()[..] == "Self"
&& t.get_super()
.is_some_and(|sup| ctx.supertype_of(&sup, subtype))
&& t.get_super().is_some_and(|sup| {
let fv = t.as_free().unwrap();
fv.dummy_link();
let res = ctx.supertype_of(&sup, subtype);
fv.undo();
res
})
{
let mut _self = Self::new(ctx);
t.undoable_link(subtype, &_self.undoable_linked);

View file

@ -248,8 +248,8 @@ impl Constraint {
} else if sup.addr_eq(target) {
Self::new_supertype_of(sub)
} else {
let sub = sub.eliminate_sub(target);
let sup = sup.eliminate_sub(target);
let sub = sub.eliminate_subsup(target);
let sup = sup.eliminate_subsup(target);
Self::new_sandwiched(sub, sup)
}
}

View file

@ -37,7 +37,7 @@ use erg_parser::ast::Expr;
use erg_parser::token::TokenKind;
pub use const_subr::*;
use constructors::{dict_t, int_interval, mono};
use constructors::{callable, dict_t, int_interval, mono};
use free::{CanbeFree, Constraint, Free, FreeKind, FreeTyVar, HasLevel, Level, GENERIC_LEVEL};
pub use predicate::Predicate;
pub use typaram::{IntervalOp, TyParam};
@ -2007,7 +2007,7 @@ impl HasLevel for Type {
Some(min)
}
}
_ => None,
mono_type_pattern!() => None,
}
}
@ -2084,7 +2084,7 @@ impl HasLevel for Type {
sub.set_level(level);
sup.set_level(level);
}
_ => {}
mono_type_pattern!() => {} //_ => {}
}
}
}
@ -2874,7 +2874,11 @@ impl Type {
|| after.as_ref().map_or(false, |t| t.contains_tvar(target))
}
Self::Bounded { sub, sup } => sub.contains_tvar(target) || sup.contains_tvar(target),
_ => false,
Self::Callable { param_ts, return_t } => {
param_ts.iter().any(|t| t.contains_tvar(target)) || return_t.contains_tvar(target)
}
Self::Guard(guard) => guard.to.contains_tvar(target),
mono_type_pattern!() => false,
}
}
@ -2937,7 +2941,11 @@ impl Type {
|| after.as_ref().map_or(false, |t| t.contains_type(target))
}
Self::Bounded { sub, sup } => sub.contains_type(target) || sup.contains_type(target),
_ => false,
Self::Callable { param_ts, return_t } => {
param_ts.iter().any(|t| t.contains_type(target)) || return_t.contains_type(target)
}
Self::Guard(guard) => guard.to.contains_type(target),
mono_type_pattern!() => false,
}
}
@ -2971,13 +2979,18 @@ impl Type {
|| after.as_ref().map_or(false, |t| t.contains_tp(target))
}
Self::Bounded { sub, sup } => sub.contains_tp(target) || sup.contains_tp(target),
_ => false,
Self::Callable { param_ts, return_t } => {
param_ts.iter().any(|t| t.contains_tp(target)) || return_t.contains_tp(target)
}
Self::Guard(guard) => guard.to.contains_tp(target),
mono_type_pattern!() => false,
}
}
pub fn contains_value(&self, target: &ValueObj) -> bool {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().contains_value(target),
Self::FreeVar(_) => false,
Self::Record(rec) => rec.iter().any(|(_, t)| t.contains_value(target)),
Self::NamedTuple(rec) => rec.iter().any(|(_, t)| t.contains_value(target)),
Self::Poly { params, .. } => params.iter().any(|tp| tp.contains_value(target)),
@ -3000,7 +3013,11 @@ impl Type {
|| after.as_ref().map_or(false, |t| t.contains_value(target))
}
Self::Bounded { sub, sup } => sub.contains_value(target) || sup.contains_value(target),
_ => false,
Self::Callable { param_ts, return_t } => {
param_ts.iter().any(|t| t.contains_value(target)) || return_t.contains_value(target)
}
Self::Guard(guard) => guard.to.contains_value(target),
mono_type_pattern!() => false,
}
}
@ -3039,7 +3056,11 @@ impl Type {
|| after.as_ref().map_or(false, |t| t.contains_type(self))
}
Self::Bounded { sub, sup } => sub.contains_type(self) || sup.contains_type(self),
_ => false,
Self::Callable { param_ts, return_t } => {
param_ts.iter().any(|t| t.contains_type(self)) || return_t.contains_type(self)
}
Self::Guard(guard) => guard.to.contains_type(self),
mono_type_pattern!() => false,
}
}
@ -3518,6 +3539,7 @@ impl Type {
base
}
}
Self::FreeVar(_) => set! {},
Self::Ref(ty) => ty.qvars_inner(),
Self::RefMut { before, after } => before.qvars_inner().concat(
after
@ -3541,6 +3563,7 @@ impl Type {
Self::Refinement(refine) => refine.t.qvars_inner().concat(refine.pred.qvars()),
// ((|T| T -> T) and U).qvars() == U.qvars()
// Self::Quantified(quant) => quant.qvars(),
Self::Quantified(_) => set! {},
Self::Poly { params, .. } => params
.iter()
.fold(set! {}, |acc, tp| acc.concat(tp.qvars())),
@ -3551,7 +3574,7 @@ impl Type {
Self::Structural(ty) => ty.qvars_inner(),
Self::Guard(guard) => guard.to.qvars_inner(),
Self::Bounded { sub, sup } => sub.qvars_inner().concat(sup.qvars_inner()),
_ => set! {},
mono_type_pattern!() => set! {},
}
}
@ -3598,6 +3621,7 @@ impl Type {
param_ts.iter().any(|t| t.has_qvar()) || return_t.has_qvar()
}
Self::Subr(subr) => subr.has_qvar(),
Self::Quantified(_) => false,
// Self::Quantified(quant) => quant.has_qvar(),
Self::Record(r) => r.values().any(|t| t.has_qvar()),
Self::NamedTuple(r) => r.iter().any(|(_, t)| t.has_qvar()),
@ -3610,7 +3634,7 @@ impl Type {
Self::Structural(ty) => ty.has_qvar(),
Self::Guard(guard) => guard.to.has_qvar(),
Self::Bounded { sub, sup } => sub.has_qvar() || sup.has_qvar(),
_ => false,
mono_type_pattern!() => false,
}
}
@ -3669,7 +3693,7 @@ impl Type {
Self::Bounded { sub, sup } => {
sub.has_undoable_linked_var() || sup.has_undoable_linked_var()
}
_ => false,
mono_type_pattern!() => false,
}
}
@ -3719,7 +3743,7 @@ impl Type {
Self::Structural(ty) => ty.has_unbound_var(),
Self::Guard(guard) => guard.to.has_unbound_var(),
Self::Bounded { sub, sup } => sub.has_unbound_var() || sup.has_unbound_var(),
_ => false,
mono_type_pattern!() => false,
}
}
@ -4065,41 +4089,41 @@ impl Type {
}
Self::Subr(subr) => Self::Subr(subr.derefine()),
Self::Quantified(quant) => quant.derefine().quantify(),
other => other.clone(),
mono_type_pattern!() => self.clone(),
}
}
/// ```erg
/// (T or U).eliminate_sub(T) == U
/// ?X(<: T or U).eliminate_sub(T) == ?X(<: U)
/// (T or U).eliminate_subsup(T) == U
/// ?X(<: T or U).eliminate_subsup(T) == ?X(<: U)
/// ```
pub fn eliminate_sub(self, target: &Type) -> Self {
pub fn eliminate_subsup(self, target: &Type) -> Self {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().eliminate_sub(target),
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().eliminate_subsup(target),
Self::FreeVar(ref fv) if fv.constraint_is_sandwiched() => {
let (sub, sup) = fv.get_subsup().unwrap();
fv.do_avoiding_recursion(|| {
let sub = sub.eliminate_sub(target);
let sup = sup.eliminate_sub(target);
let sub = sub.eliminate_subsup(target);
let sup = sup.eliminate_subsup(target);
self.update_tyvar(sub, sup, None, false);
});
self
}
Self::And(l, r) => {
if l.addr_eq(target) {
return r.eliminate_sub(target);
return r.eliminate_subsup(target);
} else if r.addr_eq(target) {
return l.eliminate_sub(target);
return l.eliminate_subsup(target);
}
l.eliminate_sub(target) & r.eliminate_sub(target)
l.eliminate_subsup(target) & r.eliminate_subsup(target)
}
Self::Or(l, r) => {
if l.addr_eq(target) {
return r.eliminate_sub(target);
return r.eliminate_subsup(target);
} else if r.addr_eq(target) {
return l.eliminate_sub(target);
return l.eliminate_subsup(target);
}
l.eliminate_sub(target) | r.eliminate_sub(target)
l.eliminate_subsup(target) | r.eliminate_subsup(target)
}
other => other,
}
@ -4115,6 +4139,7 @@ impl Type {
}
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().eliminate_recursion(target),
Self::FreeVar(_) => self,
Self::Refinement(mut refine) => {
refine.t = Box::new(refine.t.eliminate_recursion(target));
refine.pred = Box::new(refine.pred.map_t(&mut |t| t.eliminate_recursion(target)));
@ -4176,7 +4201,7 @@ impl Type {
sub: Box::new(sub.eliminate_recursion(target)),
sup: Box::new(sup.eliminate_recursion(target)),
},
other => other,
mono_type_pattern!() => self,
}
}
@ -4344,7 +4369,7 @@ impl Type {
sub: Box::new(sub._replace(target, to)),
sup: Box::new(sup._replace(target, to)),
},
other => other,
mono_type_pattern!() => self,
}
}
@ -4430,7 +4455,7 @@ impl Type {
sub: Box::new(sub._replace_tp(target, to)),
sup: Box::new(sup._replace_tp(target, to)),
},
other => other,
mono_type_pattern!() => self,
}
}
@ -4507,7 +4532,7 @@ impl Type {
sub: Box::new(sub.map_tp(f)),
sup: Box::new(sup.map_tp(f)),
},
other => other,
mono_type_pattern!() => self,
}
}
@ -4629,6 +4654,7 @@ impl Type {
pub fn normalize(self) -> Self {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().normalize(),
Self::FreeVar(_) => self,
Self::Poly { name, params } => {
let params = params.into_iter().map(|tp| tp.normalize()).collect();
Self::Poly { name, params }
@ -4684,6 +4710,7 @@ impl Type {
Self::Or(l, r) => l.normalize() | r.normalize(),
Self::Not(ty) => !ty.normalize(),
Self::Structural(ty) => ty.normalize().structuralize(),
Self::Quantified(quant) => quant.normalize().quantify(),
Self::Guard(guard) => Self::Guard(GuardType::new(
guard.namespace,
guard.target,
@ -4693,7 +4720,12 @@ impl Type {
sub: Box::new(sub.normalize()),
sup: Box::new(sup.normalize()),
},
other => other,
Self::Callable { param_ts, return_t } => {
let param_ts = param_ts.into_iter().map(|t| t.normalize()).collect();
let return_t = return_t.normalize();
callable(param_ts, return_t)
}
mono_type_pattern!() => self,
}
}
@ -4735,10 +4767,12 @@ impl Type {
}*/
return;
}
let to = to.clone().eliminate_sub(self).eliminate_recursion(self);
match self {
Self::FreeVar(fv) => fv.link(&to),
Self::Refinement(refine) => refine.t.destructive_link(&to),
Self::FreeVar(fv) => {
let to = to.clone().eliminate_subsup(self).eliminate_recursion(self);
fv.link(&to);
}
Self::Refinement(refine) => refine.t.destructive_link(to),
_ => {
if DEBUG_MODE {
panic!("{self} is not a free variable");
@ -4756,10 +4790,12 @@ impl Type {
self.inc_undo_count();
return;
}
let to = to.clone().eliminate_sub(self);
match self {
Self::FreeVar(fv) => fv.undoable_link(&to),
Self::Refinement(refine) => refine.t.undoable_link(&to, list),
Self::FreeVar(fv) => {
let to = to.clone().eliminate_subsup(self);
fv.undoable_link(&to);
}
Self::Refinement(refine) => refine.t.undoable_link(to, list),
_ => {
if DEBUG_MODE {
panic!("{self} is not a free variable")
@ -4903,6 +4939,7 @@ impl Type {
.union(&sup.contained_ts())
})
}
Self::FreeVar(_) => set! { self.clone() },
Self::Refinement(refine) => refine.t.contained_ts(),
Self::Ref(t) => t.contained_ts(),
Self::RefMut { before, .. } => before.contained_ts(),
@ -4944,7 +4981,8 @@ impl Type {
ts.extend(params.iter().flat_map(|tp| tp.contained_ts()));
ts
}
_ => set! { self.clone() },
Self::Guard(guard) => guard.to.contained_ts(),
mono_type_pattern!() => set! { self.clone() },
}
}
@ -4958,6 +4996,7 @@ impl Type {
Self::FreeVar(fv) if fv.is_generalized() => {
fv.update_init();
}
Self::FreeVar(_) => {}
// TODO: T(:> X, <: Y).dereference()
Self::Refinement(refine) => {
refine.t.dereference();
@ -5034,7 +5073,7 @@ impl Type {
Self::Guard(guard) => {
guard.to.dereference();
}
_ => {}
mono_type_pattern!() => {}
}
}

View file

@ -1125,11 +1125,16 @@ impl TyParam {
base
}
}
Self::FreeVar(_) => set! {},
Self::Type(t) => t.qvars(),
Self::Proj { obj, .. } => obj.qvars(),
Self::ProjCall { obj, args, .. } => args
.iter()
.fold(obj.qvars(), |acc, arg| acc.concat(arg.qvars())),
Self::List(ts) | Self::Tuple(ts) => {
ts.iter().fold(set! {}, |acc, t| acc.concat(t.qvars()))
}
Self::UnsizedList(elem) => elem.qvars(),
Self::Set(ts) => ts.iter().fold(set! {}, |acc, t| acc.concat(t.qvars())),
Self::Dict(ts) => ts.iter().fold(set! {}, |acc, (k, v)| {
acc.concat(k.qvars().concat(v.qvars()))
@ -1146,7 +1151,7 @@ impl TyParam {
Self::App { args, .. } => args.iter().fold(set! {}, |acc, p| acc.concat(p.qvars())),
Self::Erased(t) => t.qvars(),
Self::Value(val) => val.qvars(),
_ => set! {},
Self::Mono(_) | Self::Failure => set! {},
}
}
@ -1154,9 +1159,12 @@ impl TyParam {
match self {
Self::FreeVar(fv) if fv.is_unbound() && fv.is_generalized() => true,
Self::FreeVar(fv) if fv.is_linked() => fv.crack().has_qvar(),
Self::FreeVar(_) => false,
Self::Type(t) => t.has_qvar(),
Self::Proj { obj, .. } => obj.has_qvar(),
Self::ProjCall { obj, args, .. } => obj.has_qvar() || args.iter().any(|t| t.has_qvar()),
Self::List(tps) | Self::Tuple(tps) => tps.iter().any(|tp| tp.has_qvar()),
Self::UnsizedList(elem) => elem.has_qvar(),
Self::Set(tps) => tps.iter().any(|tp| tp.has_qvar()),
Self::Dict(tps) => tps.iter().any(|(k, v)| k.has_qvar() || v.has_qvar()),
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
@ -1168,7 +1176,7 @@ impl TyParam {
Self::App { args, .. } => args.iter().any(|p| p.has_qvar()),
Self::Erased(t) => t.has_qvar(),
Self::Value(val) => val.has_qvar(),
_ => false,
Self::Mono(_) | Self::Failure => false,
}
}
@ -1178,7 +1186,11 @@ impl TyParam {
Self::Type(t) => t.contains_tvar(target),
Self::Erased(t) => t.contains_tvar(target),
Self::Proj { obj, .. } => obj.contains_tvar(target),
Self::ProjCall { obj, args, .. } => {
obj.contains_tvar(target) || args.iter().any(|t| t.contains_tvar(target))
}
Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.contains_tvar(target)),
Self::UnsizedList(elem) => elem.contains_tvar(target),
Self::Set(ts) => ts.iter().any(|t| t.contains_tvar(target)),
Self::Dict(ts) => ts
.iter()
@ -1528,8 +1540,12 @@ impl TyParam {
}
match self {
Self::FreeVar(fv) => {
let to = to.clone().eliminate_recursion(self);
fv.link(&to);
if to.contains_tp(self) {
let to = to.clone().eliminate_recursion(self);
fv.link(&to);
} else {
fv.link(to);
}
}
Self::Type(t) => {
if let Ok(to) = <&Type>::try_from(to) {
@ -1558,8 +1574,12 @@ impl TyParam {
}
match self {
Self::FreeVar(fv) => {
let to = to.clone().eliminate_recursion(self);
fv.undoable_link(&to);
if to.contains_tp(self) {
let to = to.clone().eliminate_recursion(self);
fv.undoable_link(&to);
} else {
fv.undoable_link(to);
}
}
Self::Type(t) => {
if let Ok(to) = <&Type>::try_from(to) {
@ -1672,6 +1692,7 @@ impl TyParam {
Self::FreeVar(fv) if fv.is_generalized() => {
fv.update_init();
}
Self::FreeVar(_) => {}
Self::Type(t) => t.dereference(),
Self::Value(val) => val.dereference(),
Self::App { args, .. } => {
@ -1729,7 +1750,7 @@ impl TyParam {
rhs.dereference();
}
Self::Erased(t) => t.dereference(),
_ => {}
Self::Mono(_) | Self::Failure => {}
}
}
@ -1756,6 +1777,7 @@ impl TyParam {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().variables(),
Self::FreeVar(fv) if fv.get_type().is_some() => fv.get_type().unwrap().variables(),
Self::FreeVar(_) => set! {},
Self::Mono(name) => set! { name.clone() },
Self::App { name, args } => {
let mut set = set! { name.clone() };
@ -1791,7 +1813,7 @@ impl TyParam {
}
Self::Type(t) | Self::Erased(t) => t.variables(),
Self::Value(val) => val.variables(),
_ => set! {},
Self::Failure => set! {},
}
}
@ -1799,6 +1821,12 @@ impl TyParam {
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::FreeVar(fv) if fv.get_type().is_some() => {
let typ = fv.get_type().unwrap();
fv.update_type(typ.map_tp(f));
TyParam::FreeVar(fv)
}
TyParam::FreeVar(_) => self,
TyParam::App { name, args } => {
let new_args = args.into_iter().map(f).collect::<Vec<_>>();
TyParam::app(name, new_args)
@ -1845,13 +1873,21 @@ impl TyParam {
args: args.into_iter().map(f).collect::<Vec<_>>(),
},
TyParam::Value(val) => TyParam::Value(val.map_tp(f)),
self_ => self_,
TyParam::Type(t) => TyParam::t(t.map_tp(f)),
TyParam::Erased(t) => TyParam::erased(t.map_tp(f)),
TyParam::Mono(_) | TyParam::Failure => self,
}
}
pub fn map_t(self, f: &mut impl FnMut(Type) -> Type) -> TyParam {
match self {
TyParam::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().map_t(f),
TyParam::FreeVar(fv) if fv.get_type().is_some() => {
let typ = fv.get_type().unwrap();
fv.update_type(f(typ));
TyParam::FreeVar(fv)
}
TyParam::FreeVar(_) => self,
TyParam::App { name, args } => {
let new_args = args.into_iter().map(|tp| tp.map_t(f)).collect::<Vec<_>>();
TyParam::app(name, new_args)
@ -1900,7 +1936,9 @@ impl TyParam {
}
}
TyParam::Value(val) => TyParam::Value(val.map_t(f)),
self_ => self_,
TyParam::Type(t) => TyParam::t(f(*t)),
TyParam::Erased(t) => TyParam::erased(f(*t)),
TyParam::Mono(_) | TyParam::Failure => self,
}
}