mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-29 12:24:45 +00:00
fix: infinite tyvar recursion bug
This commit is contained in:
parent
4012b323d5
commit
8c5d70ca4f
4 changed files with 29 additions and 13 deletions
|
@ -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, ")")?;
|
||||
|
|
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue