Skip to content

Commit

Permalink
fix: recursive type bug
Browse files Browse the repository at this point in the history
  • Loading branch information
mtshiba committed Sep 26, 2024
1 parent 6c57ed6 commit d90922c
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 11 deletions.
32 changes: 28 additions & 4 deletions crates/erg_compiler/context/compare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1410,12 +1410,36 @@ impl Context {
(l, r @ (TyParam::Erased(_) | TyParam::FreeVar(_))) =>
self.try_cmp(r, l).map(|ord| ord.reverse()),
(TyParam::App { name, args }, r) => {
self.eval_app(name.clone(), args.clone()).ok()
.and_then(|tp| self.try_cmp(&tp, r))
let evaled = self.eval_app(name.clone(), args.clone()).ok()?;
if evaled != TyParam::app(name.clone(), args.clone()) {
self.try_cmp(&evaled, r)
} else {
None
}
}
(l, TyParam::App { name, args }) => {
self.eval_app(name.clone(), args.clone()).ok()
.and_then(|tp| self.try_cmp(l, &tp))
let evaled = self.eval_app(name.clone(), args.clone()).ok()?;
if evaled != TyParam::app(name.clone(), args.clone()) {
self.try_cmp(l, &evaled)
} else {
None
}
}
(TyParam::Proj { obj, attr }, r) => {
let evaled = self.eval_tp_proj(*obj.clone(), attr.clone(), &()).ok()?;
if evaled != obj.clone().proj(attr.clone()) {
self.try_cmp(&evaled, r)
} else {
None
}
}
(l, TyParam::Proj { obj, attr }) => {
let evaled = self.eval_tp_proj(*obj.clone(), attr.clone(), &()).ok()?;
if evaled != obj.clone().proj(attr.clone()) {
self.try_cmp(l, &evaled)
} else {
None
}
}
(_l, _r) => {
erg_common::fmt_dbg!(_l, _r,);
Expand Down
3 changes: 3 additions & 0 deletions crates/erg_compiler/context/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1823,6 +1823,9 @@ impl Context {
}

/// args: may be unevaluated
///
/// NOTE: This function may not evaluate app and return `TyParam::app(name, args)`.
/// Be careful with recursive calls.
pub(crate) fn eval_app(&self, name: Str, args: Vec<TyParam>) -> Failable<TyParam> {
/*let args = self
.eval_type_args(args)
Expand Down
7 changes: 6 additions & 1 deletion crates/erg_compiler/context/generalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,12 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
match t {
FreeVar(fv) if fv.is_linked() => {
let t = fv.unwrap_linked();
self.deref_tyvar(t)
// (((((...))))) == Never
if t.is_recursive() {
Ok(Type::Never)
} else {
self.deref_tyvar(t)
}
}
FreeVar(mut fv)
if fv.is_generalized() && self.qnames.contains(&fv.unbound_name().unwrap()) =>
Expand Down
27 changes: 22 additions & 5 deletions crates/erg_compiler/ty/free.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use erg_common::consts::DEBUG_MODE;
use erg_common::shared::Forkable;
use erg_common::traits::{LimitedDisplay, StructuralEq};
use erg_common::Str;
use erg_common::{addr_eq, log};
use erg_common::{addr, addr_eq, log};

use super::typaram::TyParam;
use super::Type;
Expand Down Expand Up @@ -573,7 +573,12 @@ impl Hash for Free<Type> {
} else if let Some(t) = self.get_type() {
t.hash(state);
} else if self.is_linked() {
self.crack().hash(state);
let cracked = self.crack();
if !Type::FreeVar(self.clone()).addr_eq(&cracked) {
cracked.hash(state);
} else {
addr!(self).hash(state);
}
}
}
}
Expand Down Expand Up @@ -785,7 +790,7 @@ impl Free<Type> {
let placeholder_ = placeholder
.clone()
.eliminate_subsup(&target)
.eliminate_and_or_recursion(&target);
.eliminate_recursion(&target);
self.undoable_link(&placeholder_);
}
let res = f();
Expand Down Expand Up @@ -983,7 +988,13 @@ impl HasLevel for Free<Type> {
fn level(&self) -> Option<Level> {
match &*self.borrow() {
FreeKind::Unbound { lev, .. } | FreeKind::NamedUnbound { lev, .. } => Some(*lev),
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => t.level(),
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => {
if t.is_recursive() {
None
} else {
t.level()
}
}
}
}
}
Expand All @@ -1009,7 +1020,13 @@ impl HasLevel for Free<TyParam> {
fn level(&self) -> Option<Level> {
match &*self.borrow() {
FreeKind::Unbound { lev, .. } | FreeKind::NamedUnbound { lev, .. } => Some(*lev),
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => t.level(),
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => {
if t.is_recursive() {
None
} else {
t.level()
}
}
}
}
}
Expand Down
8 changes: 7 additions & 1 deletion crates/erg_compiler/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3591,7 +3591,13 @@ impl Type {
pub fn undoable_coerce(&self, list: &UndoableLinkedList) {
match self {
Type::FreeVar(fv) if fv.is_linked() => {
fv.crack().undoable_coerce(list);
let cracked = fv.crack();
if cracked.is_recursive() {
drop(cracked);
fv.undoable_link(&Type::Never);
} else {
cracked.undoable_coerce(list);
}
}
Type::FreeVar(fv) if fv.is_unbound_and_sandwiched() => {
set_recursion_limit!({}, 128);
Expand Down

0 comments on commit d90922c

Please sign in to comment.