mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-29 20:34:44 +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
|
@ -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");
|
||||||
|
|
|
@ -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()
|
||||||
};
|
};
|
||||||
|
|
|
@ -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,9 +232,15 @@ 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 } => {
|
||||||
let sub = sub.eliminate(target);
|
if sub.addr_eq(target) {
|
||||||
let sup = sup.eliminate(target);
|
Self::new_subtype_of(sup)
|
||||||
Self::new_sandwiched(sub, 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,
|
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, ")")?;
|
||||||
|
|
|
@ -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"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue