mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-03 05:54: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
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn classes_supertype_of(&self, lhs: &Type, rhs: &Type) -> (Credibility, bool) {
|
fn _nominal_subtype_of<'c>(
|
||||||
if !self.is_class(lhs) || !self.is_class(rhs) {
|
&'c self,
|
||||||
return (Maybe, false);
|
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 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) {
|
if let Err(err) = self.substitute_typarams(typ, rhs) {
|
||||||
Self::undo_substitute_typarams(typ);
|
Self::undo_substitute_typarams(typ);
|
||||||
if DEBUG_MODE {
|
if DEBUG_MODE {
|
||||||
panic!("{typ} / {rhs}: err: {err}");
|
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)
|
// Not `supertype_of` (only structures are compared)
|
||||||
match Self::cheap_supertype_of(lhs, rhs_sup) {
|
match Self::cheap_supertype_of(lhs, rhs_sup) {
|
||||||
(Absolutely, true) => {
|
(Absolutely, true) => {
|
||||||
Self::undo_substitute_typarams(typ);
|
if substitute || overwrite {
|
||||||
|
Self::undo_substitute_typarams(typ);
|
||||||
|
}
|
||||||
return (Absolutely, true);
|
return (Absolutely, true);
|
||||||
}
|
}
|
||||||
(Maybe, _) => {
|
(Maybe, _) => {
|
||||||
if self.structural_supertype_of(lhs, rhs_sup) {
|
if self.structural_supertype_of(lhs, rhs_sup) {
|
||||||
Self::undo_substitute_typarams(typ);
|
if substitute || overwrite {
|
||||||
|
Self::undo_substitute_typarams(typ);
|
||||||
|
}
|
||||||
return (Absolutely, true);
|
return (Absolutely, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::undo_substitute_typarams(typ);
|
if substitute || overwrite {
|
||||||
|
Self::undo_substitute_typarams(typ);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(Maybe, false)
|
(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
|
// e.g. Eq(Nat) :> Nat
|
||||||
// Nat.super_traits = [Add(Nat), Eq(Nat), Sub(Float), ...]
|
// Nat.super_traits = [Add(Nat), Eq(Nat), Sub(Float), ...]
|
||||||
// e.g. Eq :> ?L or ?R (if ?L <: Eq and ?R <: Eq)
|
// e.g. Eq :> ?L or ?R (if ?L <: Eq and ?R <: Eq)
|
||||||
|
@ -293,41 +317,7 @@ impl Context {
|
||||||
if !self.is_trait(lhs) {
|
if !self.is_trait(lhs) {
|
||||||
return (Maybe, false);
|
return (Maybe, false);
|
||||||
}
|
}
|
||||||
if let Some((typ, rhs_ctx)) = self.get_nominal_type_ctx(rhs) {
|
self._nominal_subtype_of(lhs, rhs, |ty_ctx| &ty_ctx.super_traits)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// lhs :> rhs?
|
/// lhs :> rhs?
|
||||||
|
|
|
@ -640,10 +640,12 @@ impl Context {
|
||||||
// In this case, there is no new information to be gained
|
// In this case, there is no new information to be gained
|
||||||
// この場合、特に新しく得られる情報はない
|
// この場合、特に新しく得られる情報はない
|
||||||
if maybe_sub == &Type::Never || maybe_sup == &Type::Obj || maybe_sup == maybe_sub {
|
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(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
// API definition was failed and inspection is useless after this
|
// API definition was failed and inspection is useless after this
|
||||||
if maybe_sub == &Type::Failure || maybe_sup == &Type::Failure {
|
if maybe_sub == &Type::Failure || maybe_sup == &Type::Failure {
|
||||||
|
log!(info "no-op:\nmaybe_sub: {maybe_sub}\nmaybe_sup: {maybe_sup}");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
self.occur(maybe_sub, maybe_sup, loc).map_err(|err| {
|
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),
|
self.get_simple_type_mismatch_hint(maybe_sup, maybe_sub),
|
||||||
)));
|
)));
|
||||||
} else if maybe_sub.has_no_unbound_var() && maybe_sup.has_no_unbound_var() {
|
} 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(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
match (maybe_sub, maybe_sup) {
|
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.constraint_is_sandwiched() && sup_fv.constraint_is_sandwiched() =>
|
||||||
{
|
{
|
||||||
if sub_fv.is_generalized() || sup_fv.is_generalized() {
|
if sub_fv.is_generalized() || sup_fv.is_generalized() {
|
||||||
|
log!(info "generalized:\nmaybe_sub: {maybe_sub}\nmaybe_sup: {maybe_sup}");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let (lsub, lsup) = sub_fv.get_subsup().unwrap();
|
let (lsub, lsup) = sub_fv.get_subsup().unwrap();
|
||||||
|
@ -1302,6 +1306,8 @@ impl Context {
|
||||||
}
|
}
|
||||||
Self::undo_substitute_typarams(sub_def_t);
|
Self::undo_substitute_typarams(sub_def_t);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
} else {
|
||||||
|
log!(err "no compatible supertype found: {maybe_sub} <: {maybe_sup}");
|
||||||
}
|
}
|
||||||
Self::undo_substitute_typarams(sub_def_t);
|
Self::undo_substitute_typarams(sub_def_t);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue