From 05cc170f3f49a55f7672df6408e7ff0728c76e0b Mon Sep 17 00:00:00 2001 From: Shunsuke Shibayama Date: Sun, 30 Jul 2023 16:51:52 +0900 Subject: [PATCH] fix: undo leak --- crates/erg_compiler/context/compare.rs | 78 +++++++++++--------------- crates/erg_compiler/context/unify.rs | 6 ++ 2 files changed, 40 insertions(+), 44 deletions(-) diff --git a/crates/erg_compiler/context/compare.rs b/crates/erg_compiler/context/compare.rs index feff86c1..bfbe227e 100644 --- a/crates/erg_compiler/context/compare.rs +++ b/crates/erg_compiler/context/compare.rs @@ -252,40 +252,64 @@ impl Context { None } - fn classes_supertype_of(&self, lhs: &Type, rhs: &Type) -> (Credibility, bool) { - if !self.is_class(lhs) || !self.is_class(rhs) { - return (Maybe, false); - } + fn _nominal_subtype_of<'c>( + &'c self, + lhs: &Type, + rhs: &Type, + op: impl FnOnce(&'c Context) -> &'c [Type], + ) -> (Credibility, bool) { if let Some((typ, ty_ctx)) = self.get_nominal_type_ctx(rhs) { - if typ.has_qvar() { + let substitute = typ.has_qvar(); + let overwrite = typ.has_undoable_linked_var(); + if substitute { if let Err(err) = self.substitute_typarams(typ, rhs) { Self::undo_substitute_typarams(typ); if DEBUG_MODE { panic!("{typ} / {rhs}: err: {err}"); } } + } else if overwrite { + if let Err(err) = self.overwrite_typarams(typ, rhs) { + Self::undo_substitute_typarams(typ); + if DEBUG_MODE { + panic!("err: {err}"); + } + } } - for rhs_sup in ty_ctx.super_classes.iter() { + for rhs_sup in op(ty_ctx) { // Not `supertype_of` (only structures are compared) match Self::cheap_supertype_of(lhs, rhs_sup) { (Absolutely, true) => { - Self::undo_substitute_typarams(typ); + if substitute || overwrite { + Self::undo_substitute_typarams(typ); + } return (Absolutely, true); } (Maybe, _) => { if self.structural_supertype_of(lhs, rhs_sup) { - Self::undo_substitute_typarams(typ); + if substitute || overwrite { + Self::undo_substitute_typarams(typ); + } return (Absolutely, true); } } _ => {} } } - Self::undo_substitute_typarams(typ); + if substitute || overwrite { + Self::undo_substitute_typarams(typ); + } } (Maybe, false) } + fn classes_supertype_of(&self, lhs: &Type, rhs: &Type) -> (Credibility, bool) { + if !self.is_class(lhs) || !self.is_class(rhs) { + return (Maybe, false); + } + self._nominal_subtype_of(lhs, rhs, |ty_ctx| &ty_ctx.super_classes) + } + // e.g. Eq(Nat) :> Nat // Nat.super_traits = [Add(Nat), Eq(Nat), Sub(Float), ...] // e.g. Eq :> ?L or ?R (if ?L <: Eq and ?R <: Eq) @@ -293,41 +317,7 @@ impl Context { if !self.is_trait(lhs) { return (Maybe, false); } - if let Some((typ, rhs_ctx)) = self.get_nominal_type_ctx(rhs) { - if typ.has_qvar() { - if let Err(err) = self.substitute_typarams(typ, rhs) { - Self::undo_substitute_typarams(typ); - if DEBUG_MODE { - panic!("err: {err}"); - } - } - } else if typ.has_undoable_linked_var() { - if let Err(err) = self.overwrite_typarams(typ, rhs) { - Self::undo_substitute_typarams(typ); - if DEBUG_MODE { - panic!("err: {err}"); - } - } - } - for rhs_sup in rhs_ctx.super_traits.iter() { - // Not `supertype_of` (only structures are compared) - match Self::cheap_supertype_of(lhs, rhs_sup) { - (Absolutely, true) => { - Self::undo_substitute_typarams(typ); - return (Absolutely, true); - } - (Maybe, _) => { - if self.structural_supertype_of(lhs, rhs_sup) { - Self::undo_substitute_typarams(typ); - return (Absolutely, true); - } - } - _ => {} - } - } - Self::undo_substitute_typarams(typ); - } - (Maybe, false) + self._nominal_subtype_of(lhs, rhs, |ty_ctx| &ty_ctx.super_traits) } /// lhs :> rhs? diff --git a/crates/erg_compiler/context/unify.rs b/crates/erg_compiler/context/unify.rs index 3dea6fb8..39c90d15 100644 --- a/crates/erg_compiler/context/unify.rs +++ b/crates/erg_compiler/context/unify.rs @@ -640,10 +640,12 @@ impl Context { // In this case, there is no new information to be gained // この場合、特に新しく得られる情報はない if maybe_sub == &Type::Never || maybe_sup == &Type::Obj || maybe_sup == maybe_sub { + log!(info "no-op:\nmaybe_sub: {maybe_sub}\nmaybe_sup: {maybe_sup}"); return Ok(()); } // API definition was failed and inspection is useless after this if maybe_sub == &Type::Failure || maybe_sup == &Type::Failure { + log!(info "no-op:\nmaybe_sub: {maybe_sub}\nmaybe_sup: {maybe_sup}"); return Ok(()); } self.occur(maybe_sub, maybe_sup, loc).map_err(|err| { @@ -666,6 +668,7 @@ impl Context { self.get_simple_type_mismatch_hint(maybe_sup, maybe_sub), ))); } else if maybe_sub.has_no_unbound_var() && maybe_sup.has_no_unbound_var() { + log!(info "no-op:\nmaybe_sub: {maybe_sub}\nmaybe_sup: {maybe_sup}"); return Ok(()); } match (maybe_sub, maybe_sup) { @@ -686,6 +689,7 @@ impl Context { if sub_fv.constraint_is_sandwiched() && sup_fv.constraint_is_sandwiched() => { if sub_fv.is_generalized() || sup_fv.is_generalized() { + log!(info "generalized:\nmaybe_sub: {maybe_sub}\nmaybe_sup: {maybe_sup}"); return Ok(()); } let (lsub, lsup) = sub_fv.get_subsup().unwrap(); @@ -1302,6 +1306,8 @@ impl Context { } Self::undo_substitute_typarams(sub_def_t); return Ok(()); + } else { + log!(err "no compatible supertype found: {maybe_sub} <: {maybe_sup}"); } Self::undo_substitute_typarams(sub_def_t); }