Skip to content

Commit

Permalink
fix: infinite recursion bug
Browse files Browse the repository at this point in the history
  • Loading branch information
mtshiba committed Apr 12, 2023
1 parent 827f755 commit 9f110ae
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 14 deletions.
4 changes: 2 additions & 2 deletions crates/erg_compiler/context/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1119,8 +1119,8 @@ impl Context {
level: usize,
t_loc: &impl Locational,
) -> EvalResult<Type> {
if lhs == Never {
return Ok(Never);
if let Never | Failure = lhs {
return Ok(lhs);
}
// Currently Erg does not allow projection-types to be evaluated with type variables included.
// All type variables will be dereferenced or fail.
Expand Down
16 changes: 12 additions & 4 deletions crates/erg_compiler/context/generalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,10 +516,18 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
// we need to force linking to avoid infinite loop
// e.g. fv == ?T(<: Int, :> Add(?T))
// fv == ?T(:> ?T.Output, <: Add(Int))
if sub_t.contains(&Type::FreeVar(fv.clone())) {
fv.forced_undoable_link(&super_t);
} else {
fv.forced_undoable_link(&sub_t);
let fv_t = Type::FreeVar(fv.clone());
match (sub_t.contains(&fv_t), super_t.contains(&fv_t)) {
// REVIEW: to prevent infinite recursion, but this may cause a nonsense error
(true, true) => {
fv.dummy_link();
}
(true, false) => {
fv.forced_undoable_link(&super_t);
}
(false, true | false) => {
fv.forced_undoable_link(&sub_t);
}
}
let res = self.validate_subsup(sub_t, super_t);
fv.undo();
Expand Down
14 changes: 7 additions & 7 deletions crates/erg_compiler/context/inquire.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2786,22 +2786,22 @@ impl Context {
}

fn get_proj_candidates(&self, lhs: &Type, rhs: &Str) -> Set<Type> {
#[allow(clippy::single_match)]
match lhs {
Type::FreeVar(fv) => {
if let Some(sup) = fv.get_super() {
if self.is_trait(&sup) {
return self.get_trait_proj_candidates(&sup, rhs);
self.get_trait_proj_candidates(&sup, rhs)
} else {
return self
.eval_proj(sup, rhs.clone(), self.level, &())
.map_or(set! {}, |t| set! {t});
self.eval_proj(sup, rhs.clone(), self.level, &())
.map_or(set! {}, |t| set! {t})
}
} else {
set! {}
}
}
_ => {}
Type::Failure | Type::Never => set! { lhs.clone() },
_ => set! {},
}
set! {}
}

fn get_trait_proj_candidates(&self, trait_: &Type, rhs: &Str) -> Set<Type> {
Expand Down
7 changes: 7 additions & 0 deletions crates/erg_compiler/ty/free.rs
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,13 @@ impl<T: Clone> Free<T> {
}
}

pub fn get_linked(&self) -> Option<T> {
match &*self.borrow() {
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => Some(t.clone()),
FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => None,
}
}

pub fn detach(&self) -> Self {
match self.clone().unwrap_unbound() {
(Some(name), lev, constraint) => Self::new_named_unbound(name, lev, constraint),
Expand Down
2 changes: 1 addition & 1 deletion crates/erg_compiler/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2248,7 +2248,7 @@ impl Type {
Self::FreeVar(fv) if fv.is_generalized() => true,
Self::FreeVar(fv) => {
if let Some((sub, sup)) = fv.get_subsup() {
fv.undoable_link(&Type::Never);
fv.dummy_link();
let res_sub = sub.has_qvar();
let res_sup = sup.has_qvar();
fv.undo();
Expand Down

0 comments on commit 9f110ae

Please sign in to comment.