Skip to content

Commit 9f110ae

Browse files
committed
fix: infinite recursion bug
1 parent 827f755 commit 9f110ae

File tree

5 files changed

+29
-14
lines changed

5 files changed

+29
-14
lines changed

crates/erg_compiler/context/eval.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,8 +1119,8 @@ impl Context {
11191119
level: usize,
11201120
t_loc: &impl Locational,
11211121
) -> EvalResult<Type> {
1122-
if lhs == Never {
1123-
return Ok(Never);
1122+
if let Never | Failure = lhs {
1123+
return Ok(lhs);
11241124
}
11251125
// Currently Erg does not allow projection-types to be evaluated with type variables included.
11261126
// All type variables will be dereferenced or fail.

crates/erg_compiler/context/generalize.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -516,10 +516,18 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
516516
// we need to force linking to avoid infinite loop
517517
// e.g. fv == ?T(<: Int, :> Add(?T))
518518
// fv == ?T(:> ?T.Output, <: Add(Int))
519-
if sub_t.contains(&Type::FreeVar(fv.clone())) {
520-
fv.forced_undoable_link(&super_t);
521-
} else {
522-
fv.forced_undoable_link(&sub_t);
519+
let fv_t = Type::FreeVar(fv.clone());
520+
match (sub_t.contains(&fv_t), super_t.contains(&fv_t)) {
521+
// REVIEW: to prevent infinite recursion, but this may cause a nonsense error
522+
(true, true) => {
523+
fv.dummy_link();
524+
}
525+
(true, false) => {
526+
fv.forced_undoable_link(&super_t);
527+
}
528+
(false, true | false) => {
529+
fv.forced_undoable_link(&sub_t);
530+
}
523531
}
524532
let res = self.validate_subsup(sub_t, super_t);
525533
fv.undo();

crates/erg_compiler/context/inquire.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2786,22 +2786,22 @@ impl Context {
27862786
}
27872787

27882788
fn get_proj_candidates(&self, lhs: &Type, rhs: &Str) -> Set<Type> {
2789-
#[allow(clippy::single_match)]
27902789
match lhs {
27912790
Type::FreeVar(fv) => {
27922791
if let Some(sup) = fv.get_super() {
27932792
if self.is_trait(&sup) {
2794-
return self.get_trait_proj_candidates(&sup, rhs);
2793+
self.get_trait_proj_candidates(&sup, rhs)
27952794
} else {
2796-
return self
2797-
.eval_proj(sup, rhs.clone(), self.level, &())
2798-
.map_or(set! {}, |t| set! {t});
2795+
self.eval_proj(sup, rhs.clone(), self.level, &())
2796+
.map_or(set! {}, |t| set! {t})
27992797
}
2798+
} else {
2799+
set! {}
28002800
}
28012801
}
2802-
_ => {}
2802+
Type::Failure | Type::Never => set! { lhs.clone() },
2803+
_ => set! {},
28032804
}
2804-
set! {}
28052805
}
28062806

28072807
fn get_trait_proj_candidates(&self, trait_: &Type, rhs: &Str) -> Set<Type> {

crates/erg_compiler/ty/free.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,13 @@ impl<T: Clone> Free<T> {
864864
}
865865
}
866866

867+
pub fn get_linked(&self) -> Option<T> {
868+
match &*self.borrow() {
869+
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => Some(t.clone()),
870+
FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => None,
871+
}
872+
}
873+
867874
pub fn detach(&self) -> Self {
868875
match self.clone().unwrap_unbound() {
869876
(Some(name), lev, constraint) => Self::new_named_unbound(name, lev, constraint),

crates/erg_compiler/ty/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2248,7 +2248,7 @@ impl Type {
22482248
Self::FreeVar(fv) if fv.is_generalized() => true,
22492249
Self::FreeVar(fv) => {
22502250
if let Some((sub, sup)) = fv.get_subsup() {
2251-
fv.undoable_link(&Type::Never);
2251+
fv.dummy_link();
22522252
let res_sub = sub.has_qvar();
22532253
let res_sup = sup.has_qvar();
22542254
fv.undo();

0 commit comments

Comments
 (0)