diff --git a/crates/erg_compiler/context/inquire.rs b/crates/erg_compiler/context/inquire.rs index a435a02e..f91b17bf 100644 --- a/crates/erg_compiler/context/inquire.rs +++ b/crates/erg_compiler/context/inquire.rs @@ -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()); diff --git a/crates/erg_compiler/context/instantiate.rs b/crates/erg_compiler/context/instantiate.rs index 9b5684d7..a7433a10 100644 --- a/crates/erg_compiler/context/instantiate.rs +++ b/crates/erg_compiler/context/instantiate.rs @@ -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")), )?; diff --git a/crates/erg_compiler/context/unify.rs b/crates/erg_compiler/context/unify.rs index 85b5ac4a..c6efa731 100644 --- a/crates/erg_compiler/context/unify.rs +++ b/crates/erg_compiler/context/unify.rs @@ -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, diff --git a/tests/should_err/mut_list.er b/tests/should_err/mut_list.er index 19103446..52a15ab4 100644 --- a/tests/should_err/mut_list.er +++ b/tests/should_err/mut_list.er @@ -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 diff --git a/tests/test.rs b/tests/test.rs index cc90e6ae..a3342939 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -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]