diff --git a/crates/erg_compiler/context/inquire.rs b/crates/erg_compiler/context/inquire.rs index 24dc76eb..4409ad75 100644 --- a/crates/erg_compiler/context/inquire.rs +++ b/crates/erg_compiler/context/inquire.rs @@ -1361,8 +1361,9 @@ impl Context { } } } + let mut checked = vec![]; for ctx in self - .get_nominal_super_type_ctxs(obj.ref_t()) + .get_nominal_super_type_ctxs(&obj.ref_t().lower_bounded()) .ok_or_else(|| { TyCheckError::type_not_found( self.cfg.input.clone(), @@ -1373,6 +1374,7 @@ impl Context { ) })? { + checked.push(&ctx.typ); if let Some(vi) = ctx.get_current_scope_non_param(&attr_name.name) { self.validate_visibility(attr_name, vi, input, namespace)?; return Ok(vi.clone()); @@ -1395,6 +1397,45 @@ impl Context { } } } + if obj.ref_t() != &obj.ref_t().lower_bounded() { + for ctx in self + .get_nominal_super_type_ctxs(obj.ref_t()) + .ok_or_else(|| { + TyCheckError::type_not_found( + self.cfg.input.clone(), + line!() as usize, + obj.loc(), + self.caused_by(), + obj.ref_t(), + ) + })? + { + if checked.contains(&&ctx.typ) { + continue; + } + if let Some(vi) = ctx.get_current_scope_non_param(&attr_name.name) { + self.validate_visibility(attr_name, vi, input, namespace)?; + return Ok(vi.clone()); + } + for methods_ctx in ctx.methods_list.iter() { + if let Some(vi) = methods_ctx.get_current_scope_non_param(&attr_name.name) { + self.validate_visibility(attr_name, vi, input, namespace)?; + return Ok(vi.clone()); + } + } + if let Some(ctx) = self.get_same_name_context(&ctx.name) { + match ctx.rec_get_var_info(attr_name, AccessKind::BoundAttr, input, namespace) { + Triple::Ok(t) => { + return Ok(t); + } + Triple::Err(e) => { + return Err(e); + } + Triple::None => {} + } + } + } + } match self.get_attr_type_by_name(obj, attr_name, namespace) { Triple::Ok(method) => { let def_t = self @@ -3013,6 +3054,7 @@ impl Context { /// ```erg /// get_nominal_super_type_ctx(Nat) == [, , , ..., , , ...] /// get_nominal_super_type_ctx({Nat}) == [, , , ...] + /// get_nominal_super_type_ctx(?T(:> Nat, <: Eq)) == == [, ...] /// ``` pub fn get_nominal_super_type_ctxs<'a>(&'a self, t: &Type) -> Option> { match t { diff --git a/tests/should_err/subtyping.er b/tests/should_err/subtyping.er index a13f7091..39b62125 100644 --- a/tests/should_err/subtyping.er +++ b/tests/should_err/subtyping.er @@ -22,6 +22,12 @@ for! zip([1], ["a"]), ((i: Str, s: Str),) => # ERR for! zip([1], ["a"]), ((i, s),) => k = i + "a" # ERR print! k +for! zip([1], ["a"]), (is) => + i = is[0] + s = is[1] + k = i + "a" # ERR + _ = s + 1 # ERR + print! k for! zip([1+1], ["a"+"b"]), ((i, s),) => # i: Nat, s: Str print! i + 1 diff --git a/tests/test.rs b/tests/test.rs index a43b6422..596ca57a 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -716,7 +716,7 @@ fn exec_structural_err() -> Result<(), ()> { #[test] fn exec_subtyping_err() -> Result<(), ()> { // NOTE: The content of some errors is semantically redundant and can be reduced. - expect_failure("tests/should_err/subtyping.er", 3, 13) + expect_failure("tests/should_err/subtyping.er", 3, 15) } #[test]