fix: sub-unification bug of self

This commit is contained in:
Shunsuke Shibayama 2025-02-22 01:04:01 +09:00
parent 29d270c0b3
commit 1a2924512b
5 changed files with 54 additions and 6 deletions

View file

@ -859,7 +859,8 @@ impl Context {
return Triple::Err(errs);
}
drop(list);
let res = self.sub_unify(obj.ref_t(), self_t, obj, Some(&"self".into()));
let res =
self.self_unify(obj.ref_t(), self_t, &vi.t, obj, Some(&"self".into()));
if DEBUG_MODE {
res.unwrap();
}
@ -2150,7 +2151,13 @@ impl Context {
let non_default_params = if is_method_call {
let mut non_default_params = subr.non_default_params.iter();
let self_pt = non_default_params.next().unwrap();
if let Err(mut es) = self.sub_unify(obj.ref_t(), self_pt.typ(), obj, self_pt.name()) {
if let Err(mut es) = self.self_unify(
obj.ref_t(),
self_pt.typ(),
&Type::Subr(subr.clone()),
obj,
self_pt.name(),
) {
errs.append(&mut es);
}
passed_params.insert("self".into());

View file

@ -1037,7 +1037,13 @@ impl Context {
let mut tmp_tv_cache = TyVarCache::new(self.level, self);
let ty = self.instantiate_t_inner(*quant, &mut tmp_tv_cache, callee)?;
if let Some(self_t) = ty.self_t() {
self.sub_unify(callee.ref_t(), self_t, callee, Some(&Str::ever("self")))?;
self.self_unify(
callee.ref_t(),
self_t,
&ty,
callee,
Some(&Str::ever("self")),
)?;
}
if DEBUG_MODE && ty.has_qvar() {
panic!("{ty} has qvar")
@ -1050,9 +1056,10 @@ impl Context {
match &t {
Type::Subr(subr) => {
if let Some(self_t) = subr.self_t() {
self.sub_unify(
self.self_unify(
callee.ref_t(),
self_t,
&t,
callee,
Some(&Str::ever("self")),
)?;
@ -1061,9 +1068,10 @@ impl Context {
Type::And(tys, _) => {
for ty in tys {
if let Some(self_t) = ty.self_t() {
self.sub_unify(
self.self_unify(
callee.ref_t(),
self_t,
ty,
callee,
Some(&Str::ever("self")),
)?;

View file

@ -2267,6 +2267,33 @@ impl Context {
unifier.sub_unify(maybe_sub, maybe_super)
}
pub(crate) fn self_unify(
&self,
sub_self: &Type,
super_self: &Type,
subr: &Type,
loc: &impl Locational,
param_name: Option<&Str>,
) -> TyCheckResult<()> {
let unifier = Unifier::new(self, loc, None, false, param_name.cloned());
unifier.sub_unify(sub_self, super_self)?;
let super_self = match super_self {
Type::Ref(inner) => inner,
Type::RefMut { before, .. } => before,
_ => super_self,
};
let sub_self = sub_self.derefine();
if self.subtype_of(super_self, &sub_self) {
if let Some(return_t) = subr.return_t() {
if return_t.has_no_unbound_var() && !return_t.contains_type(&sub_self) {
// callee.ref_t() == self_t
let _ = unifier.sub_unify(super_self, &sub_self);
}
}
}
Ok(())
}
pub(crate) fn sub_unify_with_coercion(
&self,
maybe_sub: &Type,

View file

@ -14,3 +14,9 @@ i_s.push! None # ERR
_: List!(Int, _) = !["a"] # ERR
_: List!(Int, 1) = ![1, 2] # ERR
C! = Class(List!(List!(Int)))
C!.
append! ref! self =
self::base.insert! 0, !["a"] # ERR
self::base.insert! 0, [1] # ERR

View file

@ -766,7 +766,7 @@ fn exec_mut_err() -> Result<(), ()> {
#[test]
fn exec_mut_list_err() -> Result<(), ()> {
expect_compile_failure("tests/should_err/mut_list.er", 0, 5)
expect_compile_failure("tests/should_err/mut_list.er", 0, 7)
}
#[test]