fix: undo leak

This commit is contained in:
Shunsuke Shibayama 2023-07-30 16:51:52 +09:00
parent df7dbcda4b
commit 05cc170f3f
2 changed files with 40 additions and 44 deletions

View file

@ -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?

View file

@ -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);
}