fix: infinite tyvar recursion bug

This commit is contained in:
Shunsuke Shibayama 2023-10-20 23:10:47 +09:00
parent 4012b323d5
commit 8c5d70ca4f
4 changed files with 29 additions and 13 deletions

View file

@ -4,6 +4,7 @@ use std::hash::{Hash, Hasher};
use std::mem;
use std::sync::atomic::AtomicUsize;
use erg_common::consts::{BACKTRACE_MODE, DEBUG_MODE};
use erg_common::shared::Forkable;
use erg_common::traits::{LimitedDisplay, StructuralEq};
use erg_common::{addr, Str};
@ -76,7 +77,7 @@ impl LimitedDisplay for Constraint {
Self::Sandwiched { sub, sup } => match (sub == &Type::Never, sup == &Type::Obj) {
(true, true) => {
write!(f, ": Type")?;
if cfg!(feature = "debug") {
if DEBUG_MODE {
write!(f, "(:> Never, <: Obj)")?;
}
Ok(())
@ -231,9 +232,15 @@ impl Constraint {
pub fn eliminate_recursion(self, target: &Type) -> Self {
match self {
Self::Sandwiched { sub, sup } => {
let sub = sub.eliminate(target);
let sup = sup.eliminate(target);
Self::new_sandwiched(sub, sup)
if sub.addr_eq(target) {
Self::new_subtype_of(sup)
} else if sup.addr_eq(target) {
Self::new_supertype_of(sub)
} else {
let sub = sub.eliminate(target);
let sup = sup.eliminate(target);
Self::new_sandwiched(sub, sup)
}
}
other => other,
}
@ -370,7 +377,7 @@ impl<T: LimitedDisplay> LimitedDisplay for FreeKind<T> {
}
match self {
Self::Linked(t) | Self::UndoableLinked { t, .. } => {
if cfg!(feature = "debug") {
if DEBUG_MODE || BACKTRACE_MODE {
write!(f, "(")?;
t.limited_fmt(f, limit)?;
write!(f, ")")
@ -385,14 +392,14 @@ impl<T: LimitedDisplay> LimitedDisplay for FreeKind<T> {
} => {
if *lev == GENERIC_LEVEL {
write!(f, "{name}")?;
if cfg!(feature = "debug") {
if DEBUG_MODE || BACKTRACE_MODE {
write!(f, "(")?;
constraint.limited_fmt(f, limit - 1)?;
write!(f, ")")?;
}
} else {
write!(f, "?{name}")?;
if cfg!(feature = "debug") {
if DEBUG_MODE || BACKTRACE_MODE {
write!(f, "(")?;
constraint.limited_fmt(f, limit - 1)?;
write!(f, ")")?;
@ -408,14 +415,14 @@ impl<T: LimitedDisplay> LimitedDisplay for FreeKind<T> {
} => {
if *lev == GENERIC_LEVEL {
write!(f, "%{id}")?;
if cfg!(feature = "debug") {
if DEBUG_MODE || BACKTRACE_MODE {
write!(f, "(")?;
constraint.limited_fmt(f, limit - 1)?;
write!(f, ")")?;
}
} else {
write!(f, "?{id}")?;
if cfg!(feature = "debug") {
if DEBUG_MODE || BACKTRACE_MODE {
write!(f, "(")?;
constraint.limited_fmt(f, limit - 1)?;
write!(f, ")")?;

View file

@ -3295,6 +3295,13 @@ impl Type {
let t = fv.crack().clone();
t.eliminate(target)
}
Self::FreeVar(ref fv) if fv.constraint_is_sandwiched() => {
let (sub, sup) = fv.get_subsup().unwrap();
let sub = sub.eliminate(target);
let sup = sup.eliminate(target);
self.update_tyvar(sub, sup, None, false);
self
}
Self::And(l, r) => {
if l.addr_eq(target) {
return r.eliminate(target);
@ -3555,9 +3562,10 @@ impl Type {
if self.level() == Some(GENERIC_LEVEL) {
panic!("{self} is fixed");
}
let to = to.clone().eliminate(self);
match self {
Self::FreeVar(fv) => fv.link(to),
Self::Refinement(refine) => refine.t.destructive_link(to),
Self::FreeVar(fv) => fv.link(&to),
Self::Refinement(refine) => refine.t.destructive_link(&to),
_ => panic!("{self} is not a free variable"),
}
}