diff --git a/crates/erg_compiler/context/inquire.rs b/crates/erg_compiler/context/inquire.rs index 4b4ab1f99..83c77c9e0 100644 --- a/crates/erg_compiler/context/inquire.rs +++ b/crates/erg_compiler/context/inquire.rs @@ -19,7 +19,7 @@ use erg_common::{ use erg_parser::ast::{self, Identifier, VarName}; use erg_parser::token::Token; -use crate::ty::constructors::{anon, free_var, func, mono, poly, proc, proj, ref_, subr_t}; +use crate::ty::constructors::{anon, fn_met, free_var, func, mono, poly, proc, proj, ref_, subr_t}; use crate::ty::free::Constraint; use crate::ty::typaram::TyParam; use crate::ty::value::{GenTypeObj, TypeObj, ValueObj}; @@ -675,6 +675,7 @@ impl Context { /// get type from given attributive type (Record). /// not ModuleType or ClassType etc. + /// if `t == Never`, returns `VarInfo::ILLEGAL` fn get_attr_info_from_attributive( &self, t: &Type, @@ -728,6 +729,8 @@ impl Context { &self, obj: &hir::Expr, attr_name: &Option, + pos_args: &[hir::PosArg], + kw_args: &[hir::KwArg], input: &Input, namespace: &Context, ) -> SingleTyCheckResult { @@ -745,7 +748,7 @@ impl Context { }); } if let Some(attr_name) = attr_name.as_ref() { - self.search_method_info(obj, attr_name, input, namespace) + self.search_method_info(obj, attr_name, pos_args, kw_args, input, namespace) } else { Ok(VarInfo { t: obj.t(), @@ -766,6 +769,8 @@ impl Context { &self, obj: &hir::Expr, attr_name: &Identifier, + pos_args: &[hir::PosArg], + kw_args: &[hir::KwArg], input: &Input, namespace: &Context, ) -> SingleTyCheckResult { @@ -887,6 +892,47 @@ impl Context { let coerced = self .deref_tyvar(obj.t(), Variance::Covariant, &set! {}, obj) .map_err(|mut errs| errs.remove(0))?; + // search_method_info(?T, aaa, pos_args: [1, 2]) == None + // => ?T(<: Structural({ .aaa = (self: ?T, ?U, ?V) -> ?W })) + if coerced == Never && cfg!(feature = "py_compatible") && self.in_subr() { + let nd_params = pos_args + .iter() + .map(|_| ParamTy::Pos(free_var(self.level, Constraint::new_type_of(Type)))) + .collect::>(); + let d_params = kw_args + .iter() + .map(|arg| { + ParamTy::kw( + arg.keyword.inspect().clone(), + free_var(self.level, Constraint::new_type_of(Type)), + ) + }) + .collect::>(); + let return_t = free_var(self.level, Constraint::new_type_of(Type)); + let subr_t = fn_met(obj.t(), nd_params, None, d_params, return_t); + if let Type::FreeVar(fv) = obj.ref_t() { + if fv.get_sub().is_some() { + let vis = self.instantiate_vis_modifier(&attr_name.vis).unwrap(); + let structural = Type::Record( + dict! { Field::new(vis, attr_name.inspect().clone()) => subr_t.clone() }, + ) + .structuralize(); + fv.update_super(|_| structural); + } + } + let muty = Mutability::from(&attr_name.inspect()[..]); + let vi = VarInfo::new( + subr_t, + muty, + Visibility::DUMMY_PUBLIC, + VarKind::Builtin, + None, + None, + None, + AbsLocation::unknown(), + ); + return Ok(vi); + } if &coerced == obj.ref_t() { Err(TyCheckError::no_attr_error( self.cfg.input.clone(), @@ -899,7 +945,7 @@ impl Context { )) } else { obj.ref_t().coerce(); - self.search_method_info(obj, attr_name, input, namespace) + self.search_method_info(obj, attr_name, pos_args, kw_args, input, namespace) } } @@ -1644,7 +1690,7 @@ impl Context { } } let found = self - .search_callee_info(obj, attr_name, input, namespace) + .search_callee_info(obj, attr_name, pos_args, kw_args, input, namespace) .map_err(|err| (None, TyCheckErrors::from(err)))?; log!( "Found:\ncallee: {obj}{}\nfound: {found}", diff --git a/crates/erg_compiler/context/unify.rs b/crates/erg_compiler/context/unify.rs index 510cfd21f..f7010e8cd 100644 --- a/crates/erg_compiler/context/unify.rs +++ b/crates/erg_compiler/context/unify.rs @@ -687,47 +687,40 @@ impl Context { Ok(()) } (_, Type::FreeVar(rfv)) if rfv.is_unbound() => { - // NOTE: cannot `borrow_mut` because of cycle reference - let rfv_ref = unsafe { rfv.as_ptr().as_mut().unwrap() }; - match rfv_ref { - FreeKind::NamedUnbound { constraint, .. } - | FreeKind::Unbound { constraint, .. } => match constraint { - // * sub_unify(Nat, ?E(<: Eq(?E))) - // sub !<: l => OK (sub will widen) - // sup !:> l => Error - // * sub_unify(Str, ?T(:> _, <: Int)): (/* Error */) - // * sub_unify(Ratio, ?T(:> _, <: Int)): (/* Error */) - // sub = max(l, sub) if max exists - // * sub_unify(Nat, ?T(:> Int, <: _)): (/* OK */) - // * sub_unify(Int, ?T(:> Nat, <: Obj)): (?T(:> Int, <: Obj)) - // * sub_unify(Nat, ?T(:> Never, <: Add(?R))): (?T(:> Nat, <: Add(?R)) - // sub = union(l, sub) if max does not exist - // * sub_unify(Str, ?T(:> Int, <: Obj)): (?T(:> Str or Int, <: Obj)) - // * sub_unify({0}, ?T(:> {1}, <: Nat)): (?T(:> {0, 1}, <: Nat)) - // * sub_unify(Bool, ?T(<: Bool or Y)): (?T == Bool) - // * sub_unify(Float, ?T(<: Structural{ .imag = ?U })) ==> ?U == Float - Constraint::Sandwiched { sub, sup } => { - if sup.is_structural() { - self.sub_unify(maybe_sub, sup, loc, param_name)?; - } - let new_sub = self.union(maybe_sub, sub); - if sup.contains_union(&new_sub) { - rfv.link(&new_sub); // Bool <: ?T <: Bool or Y ==> ?T == Bool - } else { - *constraint = Constraint::new_sandwiched(new_sub, mem::take(sup)); - } - } - // sub_unify(Nat, ?T(: Type)): (/* ?T(:> Nat) */) - Constraint::TypeOf(ty) => { - if self.supertype_of(&Type, ty) { - *constraint = Constraint::new_supertype_of(maybe_sub.clone()); - } else { - todo!() - } - } - Constraint::Uninited => unreachable!(), - }, - _ => {} + // * sub_unify(Nat, ?E(<: Eq(?E))) + // sub !<: l => OK (sub will widen) + // sup !:> l => Error + // * sub_unify(Str, ?T(:> _, <: Int)): (/* Error */) + // * sub_unify(Ratio, ?T(:> _, <: Int)): (/* Error */) + // sub = max(l, sub) if max exists + // * sub_unify(Nat, ?T(:> Int, <: _)): (/* OK */) + // * sub_unify(Int, ?T(:> Nat, <: Obj)): (?T(:> Int, <: Obj)) + // * sub_unify(Nat, ?T(:> Never, <: Add(?R))): (?T(:> Nat, <: Add(?R)) + // sub = union(l, sub) if max does not exist + // * sub_unify(Str, ?T(:> Int, <: Obj)): (?T(:> Str or Int, <: Obj)) + // * sub_unify({0}, ?T(:> {1}, <: Nat)): (?T(:> {0, 1}, <: Nat)) + // * sub_unify(Bool, ?T(<: Bool or Y)): (?T == Bool) + // * sub_unify(Float, ?T(<: Structural{ .imag = ?U })) ==> ?U == Float + if let Some((sub, mut sup)) = rfv.get_subsup() { + if sup.is_structural() { + self.sub_unify(maybe_sub, &sup, loc, param_name)?; + } + let new_sub = self.union(maybe_sub, &sub); + if sup.contains_union(&new_sub) { + rfv.link(&new_sub); // Bool <: ?T <: Bool or Y ==> ?T == Bool + } else { + let constr = Constraint::new_sandwiched(new_sub, mem::take(&mut sup)); + rfv.update_constraint(constr, true); + } + } + // sub_unify(Nat, ?T(: Type)): (/* ?T(:> Nat) */) + else if let Some(ty) = rfv.get_type() { + if self.supertype_of(&Type, &ty) { + let constr = Constraint::new_supertype_of(maybe_sub.clone()); + rfv.update_constraint(constr, true); + } else { + todo!() + } } Ok(()) } @@ -750,43 +743,41 @@ impl Context { self.sub_unify(maybe_sub, t, loc, param_name) } (Type::FreeVar(lfv), _) if lfv.is_unbound() => { - let lfv_ref = unsafe { lfv.as_ptr().as_mut().unwrap() }; - match lfv_ref { - FreeKind::NamedUnbound { constraint, .. } - | FreeKind::Unbound { constraint, .. } => match constraint { - // sub !<: r => Error - // * sub_unify(?T(:> Int, <: _), Nat): (/* Error */) - // * sub_unify(?T(:> Nat, <: _), Str): (/* Error */) - // sup !:> r => Error - // * sub_unify(?T(:> _, <: Str), Int): (/* Error */) - // * sub_unify(?T(:> _, <: Int), Nat): (/* Error */) - // sub <: r, sup :> r => sup = min(sup, r) if min exists - // * sub_unify(?T(:> Never, <: Nat), Int): (/* OK */) - // * sub_unify(?T(:> Nat, <: Obj), Int): (?T(:> Nat, <: Int)) - // sup = intersection(sup, r) if min does not exist - // * sub_unify(?T(<: {1}), {0}): (* ?T == Never *) - // * sub_unify(?T(<: Eq and Ord), Show): (?T(<: Eq and Ord and Show)) - Constraint::Sandwiched { sub, sup } => { - // REVIEW: correct? - if let Some(new_sup) = self.min(sup, maybe_sup) { - *constraint = - Constraint::new_sandwiched(mem::take(sub), new_sup.clone()); - } else { - let new_sup = self.intersection(sup, maybe_sup); - *constraint = Constraint::new_sandwiched(mem::take(sub), new_sup); - } - } - // sub_unify(?T(: Type), Int): (?T(<: Int)) - Constraint::TypeOf(ty) => { - if self.supertype_of(&Type, ty) { - *constraint = Constraint::new_subtype_of(maybe_sup.clone()); - } else { - todo!() - } - } - Constraint::Uninited => unreachable!(), - }, - _ => {} + // sub !<: r => Error + // * sub_unify(?T(:> Int, <: _), Nat): (/* Error */) + // * sub_unify(?T(:> Nat, <: _), Str): (/* Error */) + // sup !:> r => Error + // * sub_unify(?T(:> _, <: Str), Int): (/* Error */) + // * sub_unify(?T(:> _, <: Int), Nat): (/* Error */) + // sub <: r, sup :> r => sup = min(sup, r) if min exists + // * sub_unify(?T(:> Never, <: Nat), Int): (/* OK */) + // * sub_unify(?T(:> Nat, <: Obj), Int): (?T(:> Nat, <: Int)) + // sup = intersection(sup, r) if min does not exist + // * sub_unify(?T(<: {1}), {0}): (* ?T == Never *) + // * sub_unify(?T(<: Eq and Ord), Show): (?T(<: Eq and Ord and Show)) + if let Some((mut sub, sup)) = lfv.get_subsup() { + if sup.is_structural() { + return Ok(()); + } + // REVIEW: correct? + if let Some(new_sup) = self.min(&sup, maybe_sup) { + let constr = + Constraint::new_sandwiched(mem::take(&mut sub), new_sup.clone()); + lfv.update_constraint(constr, true); + } else { + let new_sup = self.intersection(&sup, maybe_sup); + let constr = Constraint::new_sandwiched(mem::take(&mut sub), new_sup); + lfv.update_constraint(constr, true); + } + } + // sub_unify(?T(: Type), Int): (?T(<: Int)) + else if let Some(ty) = lfv.get_type() { + if self.supertype_of(&Type, &ty) { + let constr = Constraint::new_subtype_of(maybe_sup.clone()); + lfv.update_constraint(constr, true); + } else { + todo!() + } } Ok(()) }