mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-03 02:13:11 +00:00
fix: constraints instantiation bug
This commit is contained in:
parent
5d8506b548
commit
814748a6be
8 changed files with 69 additions and 31 deletions
|
@ -1287,7 +1287,7 @@ impl Context {
|
|||
t.clone()
|
||||
} else {
|
||||
let tv = Type::FreeVar(new_fv);
|
||||
tv_cache.push_or_init_tyvar(&name, &tv);
|
||||
tv_cache.push_or_init_tyvar(&name, &tv, self);
|
||||
tv
|
||||
}
|
||||
}
|
||||
|
|
|
@ -350,6 +350,7 @@ impl Context {
|
|||
{
|
||||
Ok(TyParam::FreeVar(fv))
|
||||
}
|
||||
// REVIEW: most likely the result of an error already made
|
||||
TyParam::FreeVar(_fv) if self.level == 0 => Err(TyCheckErrors::from(
|
||||
TyCheckError::dummy_infer_error(self.cfg.input.clone(), fn_name!(), line!()),
|
||||
)),
|
||||
|
@ -629,7 +630,11 @@ impl Context {
|
|||
let res = self.validate_subsup(sub_t, super_t, variance, qnames, loc);
|
||||
fv.undo();
|
||||
match res {
|
||||
Ok(ty) => Ok(ty),
|
||||
Ok(ty) => {
|
||||
// TODO: T(:> Nat <: Int) -> T(:> Nat, <: Int) ==> Int -> Nat
|
||||
// fv.link(&ty);
|
||||
Ok(ty)
|
||||
}
|
||||
Err(errs) => {
|
||||
fv.link(&Never);
|
||||
Err(errs)
|
||||
|
@ -637,7 +642,6 @@ impl Context {
|
|||
}
|
||||
} else {
|
||||
// no dereference at this point
|
||||
// drop(constraint);
|
||||
Ok(Type::FreeVar(fv))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -848,15 +848,23 @@ impl Context {
|
|||
}
|
||||
}
|
||||
}
|
||||
Err(TyCheckError::no_attr_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
attr_name.loc(),
|
||||
namespace.name.to_string(),
|
||||
obj.ref_t(),
|
||||
attr_name.inspect(),
|
||||
self.get_similar_attr(obj.ref_t(), attr_name.inspect()),
|
||||
))
|
||||
let coerced = self
|
||||
.deref_tyvar(obj.t(), Variance::Covariant, &set! {}, obj)
|
||||
.map_err(|mut errs| errs.remove(0))?;
|
||||
if &coerced == obj.ref_t() {
|
||||
Err(TyCheckError::no_attr_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
attr_name.loc(),
|
||||
namespace.name.to_string(),
|
||||
obj.ref_t(),
|
||||
attr_name.inspect(),
|
||||
self.get_similar_attr(obj.ref_t(), attr_name.inspect()),
|
||||
))
|
||||
} else {
|
||||
obj.ref_t().coerce();
|
||||
self.search_method_info(obj, attr_name, input, namespace)
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_visibility(
|
||||
|
|
|
@ -121,25 +121,46 @@ impl TyVarCache {
|
|||
self.already_appeared.insert(name);
|
||||
}
|
||||
|
||||
pub(crate) fn push_or_init_tyvar(&mut self, name: &Str, tv: &Type) {
|
||||
pub(crate) fn push_or_init_tyvar(&mut self, name: &Str, tv: &Type, ctx: &Context) {
|
||||
if let Some(inst) = self.tyvar_instances.get(name) {
|
||||
// T<tv> <: Eq(T<inst>)
|
||||
// T<inst> is uninitialized
|
||||
// T<inst>.link(T<tv>);
|
||||
// T <: Eq(T <: Eq(T <: ...))
|
||||
let inst = enum_unwrap!(inst, Type::FreeVar);
|
||||
inst.link(tv);
|
||||
self.update_tv(inst, tv, ctx);
|
||||
} else if let Some(inst) = self.typaram_instances.get(name) {
|
||||
if let TyParam::Type(inst) = inst {
|
||||
let fv_inst = enum_unwrap!(inst.as_ref(), Type::FreeVar);
|
||||
fv_inst.link(tv);
|
||||
self.update_tv(inst, tv, ctx);
|
||||
} else if let TyParam::FreeVar(fv) = inst {
|
||||
fv.link(&TyParam::t(tv.clone()));
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
} else {
|
||||
self.tyvar_instances.insert(name.clone(), tv.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn update_tv(&self, inst: &Type, tv: &Type, ctx: &Context) {
|
||||
// T<tv> <: Eq(T<inst>)
|
||||
// T<inst> is uninitialized
|
||||
// T<inst>.link(T<tv>);
|
||||
// T <: Eq(T <: Eq(T <: ...))
|
||||
let inst = enum_unwrap!(inst, Type::FreeVar);
|
||||
if inst.constraint_is_uninited() {
|
||||
inst.link(tv);
|
||||
} else {
|
||||
// inst: ?T(<: Int) => old_sub: Never, old_sup: Int
|
||||
// tv: ?T(:> Nat) => new_sub: Nat, new_sup: Obj
|
||||
// => ?T(:> Nat, <: Int)
|
||||
// inst: ?T(:> Str)
|
||||
// tv: ?T(:> Nat)
|
||||
// => ?T(:> Nat or Str)
|
||||
let (old_sub, old_sup) = inst.get_subsup().unwrap();
|
||||
let tv = enum_unwrap!(tv, Type::FreeVar);
|
||||
let (new_sub, new_sup) = tv.get_subsup().unwrap();
|
||||
let new_constraint = Constraint::new_sandwiched(
|
||||
ctx.union(&old_sub, &new_sub),
|
||||
ctx.intersection(&old_sup, &new_sup),
|
||||
);
|
||||
inst.update_constraint(new_constraint, true);
|
||||
}
|
||||
self.tyvar_instances.insert(name.clone(), tv.clone());
|
||||
}
|
||||
|
||||
pub(crate) fn push_or_init_typaram(&mut self, name: &Str, tp: &TyParam) {
|
||||
|
@ -147,12 +168,12 @@ impl TyVarCache {
|
|||
if let Some(_tp) = self.typaram_instances.get(name) {
|
||||
panic!("{_tp} {tp}");
|
||||
// return;
|
||||
}
|
||||
if let Some(_t) = self.tyvar_instances.get(name) {
|
||||
} else if let Some(_t) = self.tyvar_instances.get(name) {
|
||||
panic!("{_t} {tp}");
|
||||
// return;
|
||||
} else {
|
||||
self.typaram_instances.insert(name.clone(), tp.clone());
|
||||
}
|
||||
self.typaram_instances.insert(name.clone(), tp.clone());
|
||||
}
|
||||
|
||||
pub(crate) fn appeared(&self, name: &Str) -> bool {
|
||||
|
@ -386,7 +407,7 @@ impl Context {
|
|||
} else {
|
||||
if tmp_tv_cache.appeared(&name) {
|
||||
let tyvar = named_free_var(name.clone(), self.level, Constraint::Uninited);
|
||||
tmp_tv_cache.push_or_init_tyvar(&name, &tyvar);
|
||||
tmp_tv_cache.push_or_init_tyvar(&name, &tyvar, self);
|
||||
return Ok(tyvar);
|
||||
}
|
||||
if let Some(tv_ctx) = &self.tv_cache {
|
||||
|
@ -407,7 +428,7 @@ impl Context {
|
|||
tmp_tv_cache.push_appeared(name.clone());
|
||||
let constr = tmp_tv_cache.instantiate_constraint(constr, self, loc)?;
|
||||
let tyvar = named_free_var(name.clone(), self.level, constr);
|
||||
tmp_tv_cache.push_or_init_tyvar(&name, &tyvar);
|
||||
tmp_tv_cache.push_or_init_tyvar(&name, &tyvar, self);
|
||||
Ok(tyvar)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,7 +124,7 @@ impl Context {
|
|||
// TODO: other than type `Type`
|
||||
let constr = Constraint::new_type_of(Type);
|
||||
let tv = named_free_var(name.inspect().clone(), self.level, constr);
|
||||
tv_cache.push_or_init_tyvar(name.inspect(), &tv);
|
||||
tv_cache.push_or_init_tyvar(name.inspect(), &tv, self);
|
||||
Ok(())
|
||||
}
|
||||
TypeBoundSpec::NonDefault { lhs, spec } => {
|
||||
|
@ -150,7 +150,7 @@ impl Context {
|
|||
tv_cache.push_or_init_typaram(lhs.inspect(), &tp);
|
||||
} else {
|
||||
let tv = named_free_var(lhs.inspect().clone(), self.level, constr);
|
||||
tv_cache.push_or_init_tyvar(lhs.inspect(), &tv);
|
||||
tv_cache.push_or_init_tyvar(lhs.inspect(), &tv, self);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -595,7 +595,7 @@ impl Context {
|
|||
Ok(typ.clone())
|
||||
} else if not_found_is_qvar {
|
||||
let tyvar = named_free_var(Str::rc(other), self.level, Constraint::Uninited);
|
||||
tmp_tv_cache.push_or_init_tyvar(simple.ident.inspect(), &tyvar);
|
||||
tmp_tv_cache.push_or_init_tyvar(simple.ident.inspect(), &tyvar, self);
|
||||
Ok(tyvar)
|
||||
} else {
|
||||
Err(TyCheckErrors::from(TyCheckError::no_type_error(
|
||||
|
|
|
@ -838,6 +838,7 @@ impl<T: CanbeFree> Free<T> {
|
|||
self.constraint().map(|c| c.is_uninited()).unwrap_or(false)
|
||||
}
|
||||
|
||||
/// if `in_inst_or_gen` is true, constraint will be updated forcibly
|
||||
pub fn update_constraint(&self, new_constraint: Constraint, in_inst_or_gen: bool) {
|
||||
match unsafe { &mut *self.as_ptr() as &mut FreeKind<T> } {
|
||||
FreeKind::Unbound {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue