mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-03 14:04:33 +00:00
fix: undo leak
This commit is contained in:
parent
df7dbcda4b
commit
05cc170f3f
2 changed files with 40 additions and 44 deletions
|
@ -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?
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue