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

@ -8,3 +8,4 @@ pub const ERG_MODE: bool = !cfg!(feature = "py_compat");
pub const ELS: bool = cfg!(feature = "els"); pub const ELS: bool = cfg!(feature = "els");
pub const DEBUG_MODE: bool = cfg!(feature = "debug"); pub const DEBUG_MODE: bool = cfg!(feature = "debug");
pub const EXPERIMENTAL_MODE: bool = cfg!(feature = "experimental"); pub const EXPERIMENTAL_MODE: bool = cfg!(feature = "experimental");
pub const BACKTRACE_MODE: bool = cfg!(feature = "backtrace");

View file

@ -1,4 +1,4 @@
#[cfg(all(unix, any(feature = "debug", feature = "backtrace")))] #[cfg(all(unix, feature = "backtrace"))]
pub use backtrace_on_stack_overflow; pub use backtrace_on_stack_overflow;
use std::thread::{self, JoinHandle}; use std::thread::{self, JoinHandle};
@ -11,7 +11,7 @@ const STACK_SIZE: usize = if cfg!(feature = "large_thread") {
#[macro_export] #[macro_export]
macro_rules! enable_overflow_stacktrace { macro_rules! enable_overflow_stacktrace {
() => { () => {
#[cfg(all(unix, any(feature = "debug", feature = "backtrace")))] #[cfg(all(unix, feature = "backtrace"))]
unsafe { unsafe {
$crate::spawn::backtrace_on_stack_overflow::enable() $crate::spawn::backtrace_on_stack_overflow::enable()
}; };

View file

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

View file

@ -3295,6 +3295,13 @@ impl Type {
let t = fv.crack().clone(); let t = fv.crack().clone();
t.eliminate(target) 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) => { Self::And(l, r) => {
if l.addr_eq(target) { if l.addr_eq(target) {
return r.eliminate(target); return r.eliminate(target);
@ -3555,9 +3562,10 @@ impl Type {
if self.level() == Some(GENERIC_LEVEL) { if self.level() == Some(GENERIC_LEVEL) {
panic!("{self} is fixed"); panic!("{self} is fixed");
} }
let to = to.clone().eliminate(self);
match self { match self {
Self::FreeVar(fv) => fv.link(to), Self::FreeVar(fv) => fv.link(&to),
Self::Refinement(refine) => refine.t.destructive_link(to), Self::Refinement(refine) => refine.t.destructive_link(&to),
_ => panic!("{self} is not a free variable"), _ => panic!("{self} is not a free variable"),
} }
} }