diff --git a/compiler/erg_compiler/build_hir.rs b/compiler/erg_compiler/build_hir.rs index 833c1a96..02315a7d 100644 --- a/compiler/erg_compiler/build_hir.rs +++ b/compiler/erg_compiler/build_hir.rs @@ -99,7 +99,7 @@ impl HIRBuilder { Ok(hir) } - pub fn pop_ctx(&mut self) -> Context { - self.lowerer.ctx.pop() + pub fn pop_mod_ctx(&mut self) -> Context { + self.lowerer.ctx.pop_mod() } } diff --git a/compiler/erg_compiler/codegen.rs b/compiler/erg_compiler/codegen.rs index 3375fc85..46cd13e3 100644 --- a/compiler/erg_compiler/codegen.rs +++ b/compiler/erg_compiler/codegen.rs @@ -223,6 +223,7 @@ fn convert_to_python_attr(class: &str, uniq_obj_name: Option<&str>, name: Str) - ("File!", _, "read!") => Str::ever("read"), (_, _, "__new__") => Str::ever("__call__"), (_, _, "to_str") => Str::ever("__str__"), + (_, _, "__Tuple_getitem__") => Str::ever("__getitem__"), ("StringIO!", _, "getvalue!") => Str::ever("getvalue"), ("Module", Some("importlib"), "reload!") => Str::ever("reload"), ("Module", Some("random"), "randint!") => Str::ever("randint"), diff --git a/compiler/erg_compiler/context/compare.rs b/compiler/erg_compiler/context/compare.rs index a5aca769..823b8505 100644 --- a/compiler/erg_compiler/context/compare.rs +++ b/compiler/erg_compiler/context/compare.rs @@ -1,11 +1,13 @@ //! provides type-comparison use std::option::Option; // conflicting to Type::Option -use erg_common::error::Location; +use erg_common::error::{Location, MultiErrorDisplay}; + use erg_type::constructors::{and, or}; use erg_type::free::fresh_varname; use erg_type::free::{Constraint, Cyclicity, FreeKind, FreeTyVar}; -use erg_type::typaram::{TyParam, TyParamOrdering}; +use erg_type::typaram::{OpKind, TyParam, TyParamOrdering}; +use erg_type::value::ValueObj; use erg_type::value::ValueObj::Inf; use erg_type::{Predicate, RefinementType, SubrKind, SubrType, Type}; use Predicate as Pred; @@ -103,6 +105,9 @@ impl Context { FreeKind::Unbound { constraint, .. } | FreeKind::NamedUnbound { constraint, .. } => { let t = constraint.get_type().unwrap(); + if cfg!(feature = "debug") && t == &Uninited { + panic!("Uninited type variable: {fv}"); + } let other_t = self.type_of(other); return self.same_type_of(t, &other_t); } @@ -168,6 +173,7 @@ impl Context { Absolutely, rec.iter().all(|(_, attr)| self.supertype_of(&Type, attr)), ), + (Type::Uninited, _) | (_, Type::Uninited) => panic!("used an uninited type variable"), (Type, Subr(subr)) => ( Absolutely, subr.non_default_params @@ -628,7 +634,23 @@ impl Context { if ln != rn || lparams.len() != rparams.len() { return false; } - self.poly_supertype_of(lhs, lparams, rparams) + // [Int; 2] :> [Int; 3] + if &ln[..] == "Array" || &ln[..] == "Set" { + let lt = &lparams[0].as_type().unwrap(); + let rt = &rparams[0].as_type().unwrap(); + let llen = &lparams[1]; + let rlen = &rparams[1]; + self.supertype_of(lt, rt) + && self + .eval_bin_tp(OpKind::Le, llen, rlen) + .map(|tp| matches!(tp, TyParam::Value(ValueObj::Bool(true)))) + .unwrap_or_else(|e| { + e.fmt_all_stderr(); + todo!(); + }) + } else { + self.poly_supertype_of(lhs, lparams, rparams) + } } // `Eq(Set(T, N)) :> Set(T, N)` will be false, such cases are judged by nominal_supertype_of ( @@ -654,7 +676,7 @@ impl Context { (l, MonoQVar(name)) | (l, PolyQVar { name, .. }) => { panic!("internal error: not instantiated type variable: '{name}, l: {l}") } - (MonoProj { .. }, _) => { + (Proj { .. }, _) => { if let Some(cands) = self.get_candidates(lhs) { for cand in cands.into_iter() { if self.supertype_of(&cand, rhs) { @@ -664,7 +686,7 @@ impl Context { } false } - (_, MonoProj { .. }) => { + (_, Proj { .. }) => { if let Some(cands) = self.get_candidates(rhs) { for cand in cands.into_iter() { if self.supertype_of(lhs, &cand) { @@ -700,7 +722,6 @@ impl Context { super_class }; if self.cyclic_supertype_of(lhs, &sup_class) { - log!(err "引っかかった: {lhs}, {sup_class}"); return true; } } @@ -714,6 +735,11 @@ impl Context { lparams: &[TyParam], rparams: &[TyParam], ) -> bool { + log!( + "poly_supertype_of: {typ}, {}, {}", + erg_common::fmt_vec(lparams), + erg_common::fmt_vec(rparams) + ); let ctx = self .get_nominal_type_ctx(typ) .unwrap_or_else(|| panic!("{typ} is not found")); @@ -731,6 +757,18 @@ impl Context { // if matches!(r.as_ref(), &Type::Refinement(_)) { log!(info "{l}, {r}, {}", self.structural_supertype_of(l, r, bounds, Some(lhs_variance))); } self.supertype_of(l, r) } + (TyParam::FreeVar(fv), _, _) if fv.is_unbound() => { + let fv_t = fv.get_type().unwrap(); + let rp_t = self.get_tp_t(rp).unwrap(); + log!("{fv_t}, {rp_t}, {variance}"); + if variance == &Variance::Contravariant { + self.subtype_of(&fv_t, &rp_t) + } else if variance == &Variance::Covariant { + self.supertype_of(&fv_t, &rp_t) + } else { + self.same_type_of(&fv_t, &rp_t) + } + } // Invariant _ => self.eq_tp(lp, rp), }) @@ -777,10 +815,10 @@ impl Context { // try_cmp((n: 2.._), 1) -> Some(Greater) // try_cmp((n: -1.._), 1) -> Some(Any) (l @ (TyParam::Erased(_) | TyParam::FreeVar(_) | TyParam::MonoQVar(_)), p) => { - let t = self.get_tp_t(l).unwrap(); - let inf = self.inf(&t); - let sup = self.sup(&t); - if let (Some(inf), Some(sup)) = (inf, sup) { + let lt = self.get_tp_t(l).unwrap(); + let l_inf = self.inf(<); + let l_sup = self.sup(<); + if let (Some(inf), Some(sup)) = (l_inf, l_sup) { // (n: Int, 1) -> (-inf..inf, 1) -> (cmp(-inf, 1), cmp(inf, 1)) -> (Less, Greater) -> Any // (n: 5..10, 2) -> (cmp(5..10, 2), cmp(5..10, 2)) -> (Greater, Greater) -> Greater match ( @@ -935,7 +973,7 @@ impl Context { (Pred::Equal { rhs, .. }, Pred::Equal { rhs: rhs2, .. }) | (Pred::NotEqual { rhs, .. }, Pred::NotEqual { rhs: rhs2, .. }) => self .try_cmp(rhs, rhs2) - .map(|ord| ord.is_eq()) + .map(|ord| ord.canbe_eq()) .unwrap_or(false), // {T >= 0} :> {T >= 1}, {T >= 0} :> {T == 1} ( @@ -943,14 +981,14 @@ impl Context { Pred::GreaterEqual { rhs: rhs2, .. } | Pred::Equal { rhs: rhs2, .. }, ) => self .try_cmp(rhs, rhs2) - .map(|ord| ord.is_le()) + .map(|ord| ord.canbe_le()) .unwrap_or(false), ( Pred::LessEqual { rhs, .. }, Pred::LessEqual { rhs: rhs2, .. } | Pred::Equal { rhs: rhs2, .. }, ) => self .try_cmp(rhs, rhs2) - .map(|ord| ord.is_ge()) + .map(|ord| ord.canbe_ge()) .unwrap_or(false), (lhs @ (Pred::GreaterEqual { .. } | Pred::LessEqual { .. }), Pred::And(l, r)) => { self.is_super_pred_of(lhs, l) || self.is_super_pred_of(lhs, r) diff --git a/compiler/erg_compiler/context/eval.rs b/compiler/erg_compiler/context/eval.rs index 76680742..730b951d 100644 --- a/compiler/erg_compiler/context/eval.rs +++ b/compiler/erg_compiler/context/eval.rs @@ -15,8 +15,9 @@ use OpKind::*; use erg_parser::ast::*; use erg_parser::token::{Token, TokenKind}; +use erg_type::constructors::proj_method; use erg_type::constructors::{ - builtin_mono, builtin_poly, mono_proj, not, poly, ref_, ref_mut, refinement, subr_t, v_enum, + array, builtin_mono, builtin_poly, not, poly, proj, ref_, ref_mut, refinement, subr_t, v_enum, }; use erg_type::typaram::{OpKind, TyParam}; use erg_type::value::ValueObj; @@ -130,7 +131,9 @@ impl<'c> SubstContext<'c> { /// /// `ctx` is used to obtain information on the names and variance of the parameters. pub fn new(substituted: &Type, ctx: &'c Context, loc: Location) -> Self { - let ty_ctx = ctx.get_nominal_type_ctx(substituted).unwrap(); + let ty_ctx = ctx + .get_nominal_type_ctx(substituted) + .unwrap_or_else(|| todo!("{substituted} not found")); let bounds = ty_ctx.type_params_bounds(); let param_names = ty_ctx.params.iter().map(|(opt_name, _)| { opt_name @@ -203,7 +206,7 @@ impl<'c> SubstContext<'c> { TyParam::Type(t) => { self.substitute_t(t)?; } - TyParam::MonoProj { obj, .. } => { + TyParam::Proj { obj, .. } => { self.substitute_tp(obj)?; } _ => {} @@ -240,7 +243,7 @@ impl<'c> SubstContext<'c> { self.substitute_t(l)?; self.substitute_t(r)?; } - Type::MonoProj { lhs, .. } => { + Type::Proj { lhs, .. } => { self.substitute_t(lhs)?; } Type::Record(rec) => { @@ -678,6 +681,20 @@ impl Context { line!(), )) }), + Lt => lhs.try_lt(rhs).ok_or_else(|| { + EvalErrors::from(EvalError::unreachable( + self.cfg.input.clone(), + fn_name!(), + line!(), + )) + }), + Le => lhs.try_le(rhs).ok_or_else(|| { + EvalErrors::from(EvalError::unreachable( + self.cfg.input.clone(), + fn_name!(), + line!(), + )) + }), Eq => lhs.try_eq(rhs).ok_or_else(|| { EvalErrors::from(EvalError::unreachable( self.cfg.input.clone(), @@ -710,8 +727,10 @@ impl Context { .eval_bin(op, lhs.clone(), rhs.clone()) .map(TyParam::value), (TyParam::FreeVar(fv), r) if fv.is_linked() => self.eval_bin_tp(op, &*fv.crack(), r), + (TyParam::FreeVar(_), _) if op.is_comparison() => Ok(TyParam::value(true)), (TyParam::FreeVar(_), _) => Ok(TyParam::bin(op, lhs.clone(), rhs.clone())), (l, TyParam::FreeVar(fv)) if fv.is_linked() => self.eval_bin_tp(op, l, &*fv.crack()), + (_, TyParam::FreeVar(_)) if op.is_comparison() => Ok(TyParam::value(true)), (_, TyParam::FreeVar(_)) => Ok(TyParam::bin(op, lhs.clone(), rhs.clone())), (e @ TyParam::Erased(_), _) | (_, e @ TyParam::Erased(_)) => Ok(e.clone()), (l, r) => todo!("{l} {op} {r}"), @@ -759,6 +778,20 @@ impl Context { TyParam::BinOp { op, lhs, rhs } => self.eval_bin_tp(*op, lhs, rhs), TyParam::UnaryOp { op, val } => self.eval_unary_tp(*op, val), TyParam::App { name, args } => self.eval_app(name, args), + TyParam::Array(tps) => { + let mut new_tps = Vec::with_capacity(tps.len()); + for tp in tps { + new_tps.push(self.eval_tp(tp)?); + } + Ok(TyParam::Array(new_tps)) + } + TyParam::Tuple(tps) => { + let mut new_tps = Vec::with_capacity(tps.len()); + for tp in tps { + new_tps.push(self.eval_tp(tp)?); + } + Ok(TyParam::Tuple(new_tps)) + } p @ (TyParam::Type(_) | TyParam::Erased(_) | TyParam::Value(_) @@ -813,106 +846,12 @@ impl Context { // [?T; 0].MutType! == [?T; !0] // ?T(<: Add(?R(:> Int))).Output == ?T(<: Add(?R)).Output // ?T(:> Int, <: Add(?R(:> Int))).Output == Int - Type::MonoProj { lhs, rhs } => { - // Currently Erg does not allow projection-types to be evaluated with type variables included. - // All type variables will be dereferenced or fail. - let (sub, opt_sup) = match *lhs.clone() { - Type::FreeVar(fv) if fv.is_linked() => { - return self.eval_t_params(mono_proj(fv.crack().clone(), rhs), level, t_loc) - } - Type::FreeVar(fv) if fv.is_unbound() => { - let (sub, sup) = fv.get_bound_types().unwrap(); - (sub, Some(sup)) - } - other => (other, None), - }; - // cannot determine at this point - if sub == Type::Never { - return Ok(mono_proj(*lhs, rhs)); - } - for ty_ctx in self.get_nominal_super_type_ctxs(&sub).ok_or_else(|| { - EvalError::no_var_error( - self.cfg.input.clone(), - line!() as usize, - t_loc, - self.caused_by(), - &rhs, - None, // TODO: - ) - })? { - if let Ok(obj) = ty_ctx.get_const_local(&Token::symbol(&rhs), &self.name) { - if let ValueObj::Type(quant_t) = obj { - let subst_ctx = SubstContext::new(&sub, self, t_loc); - let t = subst_ctx.substitute(quant_t.typ().clone())?; - let t = self.eval_t_params(t, level, t_loc)?; - return Ok(t); - } else { - todo!() - } - } - for (class, methods) in ty_ctx.methods_list.iter() { - match (class, &opt_sup) { - (ClassDefType::ImplTrait { impl_trait, .. }, Some(sup)) => { - if !self.supertype_of(impl_trait, sup) { - continue; - } - } - (ClassDefType::ImplTrait { impl_trait, .. }, None) => { - if !self.supertype_of(impl_trait, &sub) { - continue; - } - } - _ => {} - } - if let Ok(obj) = methods.get_const_local(&Token::symbol(&rhs), &self.name) { - if let ValueObj::Type(quant_t) = obj { - let subst_ctx = SubstContext::new(&sub, self, t_loc); - let t = subst_ctx.substitute(quant_t.typ().clone())?; - let t = self.eval_t_params(t, level, t_loc)?; - return Ok(t); - } else { - todo!() - } - } - } - } - if lhs.is_unbound_var() { - let (sub, sup) = enum_unwrap!(lhs.as_ref(), Type::FreeVar) - .get_bound_types() - .unwrap(); - if self.is_trait(&sup) && !self.trait_impl_exists(&sub, &sup) { - return Err(EvalErrors::from(EvalError::no_trait_impl_error( - self.cfg.input.clone(), - line!() as usize, - &sub, - &sup, - t_loc, - self.caused_by(), - None, - ))); - } - } - // if the target can't be found in the supertype, the type will be dereferenced. - // In many cases, it is still better to determine the type variable than if the target is not found. - let coerced = self.deref_tyvar(*lhs.clone(), Variance::Covariant, t_loc)?; - if lhs.as_ref() != &coerced { - let proj = mono_proj(coerced, rhs); - self.eval_t_params(proj, level, t_loc).map(|t| { - self.coerce(&lhs); - t - }) - } else { - let proj = mono_proj(*lhs, rhs); - Err(EvalErrors::from(EvalError::no_candidate_error( - self.cfg.input.clone(), - line!() as usize, - &proj, - t_loc, - self.caused_by(), - self.get_no_candidate_hint(&proj), - ))) - } - } + Type::Proj { lhs, rhs } => self.eval_proj(*lhs, rhs, level, t_loc), + Type::ProjMethod { + lhs, + method_name, + args, + } => self.eval_proj_method(*lhs, method_name, args, level, t_loc), Type::Ref(l) => Ok(ref_(self.eval_t_params(*l, level, t_loc)?)), Type::RefMut { before, after } => { let before = self.eval_t_params(*before, level, t_loc)?; @@ -964,6 +903,197 @@ impl Context { } } + fn eval_proj(&self, lhs: Type, rhs: Str, level: usize, t_loc: Location) -> EvalResult { + // Currently Erg does not allow projection-types to be evaluated with type variables included. + // All type variables will be dereferenced or fail. + let (sub, opt_sup) = match lhs.clone() { + Type::FreeVar(fv) if fv.is_linked() => { + return self.eval_t_params(proj(fv.crack().clone(), rhs), level, t_loc) + } + Type::FreeVar(fv) if fv.is_unbound() => { + let (sub, sup) = fv.get_bound_types().unwrap(); + (sub, Some(sup)) + } + other => (other, None), + }; + // cannot determine at this point + if sub == Type::Never { + return Ok(proj(lhs, rhs)); + } + for ty_ctx in self.get_nominal_super_type_ctxs(&sub).ok_or_else(|| { + EvalError::no_var_error( + self.cfg.input.clone(), + line!() as usize, + t_loc, + self.caused_by(), + &rhs, + None, // TODO: + ) + })? { + if let Ok(obj) = ty_ctx.get_const_local(&Token::symbol(&rhs), &self.name) { + if let ValueObj::Type(quant_t) = obj { + let subst_ctx = SubstContext::new(&sub, self, t_loc); + let t = subst_ctx.substitute(quant_t.typ().clone())?; + let t = self.eval_t_params(t, level, t_loc)?; + return Ok(t); + } else { + todo!() + } + } + for (class, methods) in ty_ctx.methods_list.iter() { + match (class, &opt_sup) { + (ClassDefType::ImplTrait { impl_trait, .. }, Some(sup)) => { + if !self.supertype_of(impl_trait, sup) { + continue; + } + } + (ClassDefType::ImplTrait { impl_trait, .. }, None) => { + if !self.supertype_of(impl_trait, &sub) { + continue; + } + } + _ => {} + } + if let Ok(obj) = methods.get_const_local(&Token::symbol(&rhs), &self.name) { + if let ValueObj::Type(quant_t) = obj { + let subst_ctx = SubstContext::new(&sub, self, t_loc); + let t = subst_ctx.substitute(quant_t.typ().clone())?; + let t = self.eval_t_params(t, level, t_loc)?; + return Ok(t); + } else { + todo!() + } + } + } + } + if lhs.is_unbound_var() { + let (sub, sup) = enum_unwrap!(&lhs, Type::FreeVar).get_bound_types().unwrap(); + if self.is_trait(&sup) && !self.trait_impl_exists(&sub, &sup) { + return Err(EvalErrors::from(EvalError::no_trait_impl_error( + self.cfg.input.clone(), + line!() as usize, + &sub, + &sup, + t_loc, + self.caused_by(), + None, + ))); + } + } + // if the target can't be found in the supertype, the type will be dereferenced. + // In many cases, it is still better to determine the type variable than if the target is not found. + let coerced = self.deref_tyvar(lhs.clone(), Variance::Covariant, t_loc)?; + if lhs != coerced { + let proj = proj(coerced, rhs); + self.eval_t_params(proj, level, t_loc).map(|t| { + self.coerce(&lhs); + t + }) + } else { + let proj = proj(lhs, rhs); + Err(EvalErrors::from(EvalError::no_candidate_error( + self.cfg.input.clone(), + line!() as usize, + &proj, + t_loc, + self.caused_by(), + self.get_no_candidate_hint(&proj), + ))) + } + } + + fn eval_proj_method( + &self, + lhs: TyParam, + method_name: Str, + args: Vec, + level: usize, + t_loc: Location, + ) -> EvalResult { + let t = self.get_tp_t(&lhs)?; + for ty_ctx in self.get_nominal_super_type_ctxs(&t).ok_or_else(|| { + EvalError::no_var_error( + self.cfg.input.clone(), + line!() as usize, + t_loc, + self.caused_by(), + &method_name, + None, // TODO: + ) + })? { + if let Ok(obj) = ty_ctx.get_const_local(&Token::symbol(&method_name), &self.name) { + if let ValueObj::Subr(subr) = obj { + let is_method = subr.sig_t().self_t().is_some(); + let mut pos_args = vec![]; + if is_method { + pos_args.push(ValueObj::try_from(lhs).unwrap()); + } + for pos_arg in args.into_iter() { + pos_args.push(ValueObj::try_from(pos_arg).unwrap()); + } + let args = ValueArgs::new(pos_args, dict! {}); + let t = self.call(subr, args, None, t_loc)?; + let t = enum_unwrap!(t, ValueObj::Type); // TODO: error handling + return Ok(t.into_typ()); + } else { + todo!() + } + } + for (_class, methods) in ty_ctx.methods_list.iter() { + if let Ok(obj) = methods.get_const_local(&Token::symbol(&method_name), &self.name) { + if let ValueObj::Subr(subr) = obj { + let mut pos_args = vec![]; + for pos_arg in args.into_iter() { + pos_args.push(ValueObj::try_from(pos_arg).unwrap()); + } + let args = ValueArgs::new(pos_args, dict! {}); + let t = self.call(subr, args, None, t_loc)?; + let t = enum_unwrap!(t, ValueObj::Type); // TODO: error handling + return Ok(t.into_typ()); + } else { + todo!() + } + } + } + } + if lhs.is_unbound_var() { + let (sub, sup) = enum_unwrap!(&lhs, TyParam::FreeVar) + .get_bound_types() + .unwrap(); + if self.is_trait(&sup) && !self.trait_impl_exists(&sub, &sup) { + return Err(EvalErrors::from(EvalError::no_trait_impl_error( + self.cfg.input.clone(), + line!() as usize, + &sub, + &sup, + t_loc, + self.caused_by(), + None, + ))); + } + } + // if the target can't be found in the supertype, the type will be dereferenced. + // In many cases, it is still better to determine the type variable than if the target is not found. + let coerced = self.deref_tp(lhs.clone(), Variance::Covariant, t_loc)?; + if lhs != coerced { + let proj = proj_method(coerced, method_name, args); + self.eval_t_params(proj, level, t_loc).map(|t| { + self.coerce_tp(&lhs); + t + }) + } else { + let proj = proj_method(lhs, method_name, args); + Err(EvalErrors::from(EvalError::no_candidate_error( + self.cfg.input.clone(), + line!() as usize, + &proj, + t_loc, + self.caused_by(), + self.get_no_candidate_hint(&proj), + ))) + } + } + pub(crate) fn _eval_bound( &self, bound: TyBound, @@ -1010,8 +1140,18 @@ impl Context { todo!() } } - // TODO: Class, Trait - TyParam::Type(_) => Ok(Type::Type), + TyParam::Type(typ) => { + if let Some(ctx) = self.get_nominal_type_ctx(&typ) { + let t = match ctx.kind { + ContextKind::Class => Type::ClassType, + ContextKind::Trait | ContextKind::StructuralTrait => Type::TraitType, + _ => unreachable!(), + }; + Ok(t) + } else { + Ok(Type::Type) + } + } TyParam::Mono(name) => self .rec_get_const_obj(&name) .map(|v| v_enum(set![v.clone()])) @@ -1025,6 +1165,11 @@ impl Context { TyParam::MonoQVar(name) => { panic!("Not instantiated type variable: {name}") } + TyParam::Array(tps) => { + let tp_t = self.get_tp_t(&tps[0])?; + let t = array(tp_t, TyParam::value(tps.len())); + Ok(t) + } TyParam::UnaryOp { op, val } => match op { OpKind::Mutate => Ok(self.get_tp_t(&val)?.mutate()), _ => todo!(), diff --git a/compiler/erg_compiler/context/hint.rs b/compiler/erg_compiler/context/hint.rs index bc7a3114..dcd30eb0 100644 --- a/compiler/erg_compiler/context/hint.rs +++ b/compiler/erg_compiler/context/hint.rs @@ -49,7 +49,7 @@ impl Context { pub(crate) fn get_no_candidate_hint(&self, proj: &Type) -> Option { match proj { - Type::MonoProj { lhs, rhs: _ } => { + Type::Proj { lhs, rhs: _ } => { if let Type::FreeVar(fv) = lhs.as_ref() { let (sub, sup) = fv.get_bound_types()?; // TODO: automating diff --git a/compiler/erg_compiler/context/initialize/const_func.rs b/compiler/erg_compiler/context/initialize/const_func.rs index 35efb3ad..8ebe17ee 100644 --- a/compiler/erg_compiler/context/initialize/const_func.rs +++ b/compiler/erg_compiler/context/initialize/const_func.rs @@ -1,7 +1,7 @@ use std::mem; use std::path::PathBuf; -use erg_common::Str; +use erg_common::{enum_unwrap, Str}; use erg_common::astr::AtomicStr; use erg_common::color::{RED, RESET, YELLOW}; @@ -197,3 +197,25 @@ pub fn subsume_func( additional, )) } + +pub fn __array_getitem__( + mut args: ValueArgs, + _path: PathBuf, + __name__: Option, +) -> EvalValueResult { + let _self = enum_unwrap!(args.remove_left_or_key("Self").unwrap(), ValueObj::Array); + let index = enum_unwrap!(args.remove_left_or_key("Index").unwrap(), ValueObj::Nat); + let res = _self[index as usize].clone(); + Ok(res) +} + +pub fn __dict_getitem__( + mut args: ValueArgs, + _path: PathBuf, + __name__: Option, +) -> EvalValueResult { + let _self = enum_unwrap!(args.remove_left_or_key("Self").unwrap(), ValueObj::Dict); + let index = args.remove_left_or_key("Index").unwrap(); + let res = _self.get(&index).unwrap().clone(); + Ok(res) +} diff --git a/compiler/erg_compiler/context/initialize/mod.rs b/compiler/erg_compiler/context/initialize/mod.rs index 0bfd465e..f0cbfb7e 100644 --- a/compiler/erg_compiler/context/initialize/mod.rs +++ b/compiler/erg_compiler/context/initialize/mod.rs @@ -61,12 +61,12 @@ impl Context { } } - fn register_builtin_const(&mut self, name: &str, obj: ValueObj) { + fn register_builtin_const(&mut self, name: &str, vis: Visibility, obj: ValueObj) { if self.rec_get_const_obj(name).is_some() { panic!("already registered: {name}"); } else { // TODO: not all value objects are comparable - let vi = VarInfo::new(v_enum(set! {obj.clone()}), Const, Private, Builtin, None); + let vi = VarInfo::new(v_enum(set! {obj.clone()}), Const, vis, Builtin, None); self.consts.insert(VarName::from_str(Str::rc(name)), obj); self.locals.insert(VarName::from_str(Str::rc(name)), vi); } @@ -238,8 +238,8 @@ impl Context { let inheritable_type = Self::builtin_mono_trait("InheritableType", 2); let named = Self::builtin_mono_trait("Named", 2); let mut mutable = Self::builtin_mono_trait("Mutable", 2); - let proj = mono_proj(mono_q("Self"), "ImmutType"); - let f_t = func(vec![kw("old", proj.clone())], None, vec![], proj); + let immut_t = proj(mono_q("Self"), "ImmutType"); + let f_t = func(vec![kw("old", immut_t.clone())], None, vec![], immut_t); let t = pr1_met(ref_mut(mono_q("Self"), None), f_t, NoneType); let t = quant( t, @@ -362,22 +362,14 @@ impl Context { // Rについて共変(__add__の型とは関係ない) add.register_superclass(builtin_poly("Output", vec![ty_tp(mono_q("R"))]), &output); let self_bound = subtypeof(mono_q("Self"), builtin_poly("Add", ty_params.clone())); - let op_t = fn1_met( - mono_q("Self"), - r.clone(), - mono_proj(mono_q("Self"), "Output"), - ); + let op_t = fn1_met(mono_q("Self"), r.clone(), proj(mono_q("Self"), "Output")); let op_t = quant(op_t, set! {r_bound.clone(), self_bound}); add.register_builtin_decl("__add__", op_t, Public); add.register_builtin_decl("Output", Type, Public); /* Sub */ let mut sub = Self::builtin_poly_trait("Sub", params.clone(), 2); sub.register_superclass(builtin_poly("Output", vec![ty_tp(mono_q("R"))]), &output); - let op_t = fn1_met( - mono_q("Self"), - r.clone(), - mono_proj(mono_q("Self"), "Output"), - ); + let op_t = fn1_met(mono_q("Self"), r.clone(), proj(mono_q("Self"), "Output")); let self_bound = subtypeof(mono_q("Self"), builtin_poly("Sub", ty_params.clone())); let op_t = quant(op_t, set! {r_bound.clone(), self_bound}); sub.register_builtin_decl("__sub__", op_t, Public); @@ -385,11 +377,7 @@ impl Context { /* Mul */ let mut mul = Self::builtin_poly_trait("Mul", params.clone(), 2); mul.register_superclass(builtin_poly("Output", vec![ty_tp(mono_q("R"))]), &output); - let op_t = fn1_met( - mono_q("Self"), - r.clone(), - mono_proj(mono_q("Self"), "Output"), - ); + let op_t = fn1_met(mono_q("Self"), r.clone(), proj(mono_q("Self"), "Output")); let self_bound = subtypeof(mono_q("Self"), builtin_poly("Mul", ty_params.clone())); let op_t = quant(op_t, set! {r_bound.clone(), self_bound}); mul.register_builtin_decl("__mul__", op_t, Public); @@ -397,7 +385,7 @@ impl Context { /* Div */ let mut div = Self::builtin_poly_trait("Div", params, 2); div.register_superclass(builtin_poly("Output", vec![ty_tp(mono_q("R"))]), &output); - let op_t = fn1_met(mono_q("Self"), r, mono_proj(mono_q("Self"), "Output")); + let op_t = fn1_met(mono_q("Self"), r, proj(mono_q("Self"), "Output")); let self_bound = subtypeof(mono_q("Self"), builtin_poly("Div", ty_params.clone())); let op_t = quant(op_t, set! {r_bound, self_bound}); div.register_builtin_decl("__div__", op_t, Public); @@ -487,7 +475,11 @@ impl Context { obj_in.register_builtin_impl("__in__", fn1_met(Obj, Type, Bool), Const, Public); obj.register_trait(Obj, builtin_poly("In", vec![ty_tp(Type)]), obj_in); let mut obj_mutizable = Self::builtin_methods("Mutizable", 1); - obj_mutizable.register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Obj!"))); + obj_mutizable.register_builtin_const( + "MutType!", + Public, + ValueObj::builtin_t(builtin_mono("Obj!")), + ); obj.register_trait(Obj, builtin_mono("Mutizable"), obj_mutizable); // Obj does not implement Eq @@ -495,7 +487,7 @@ impl Context { let mut float = Self::builtin_mono_class("Float", 2); float.register_superclass(Obj, &obj); // TODO: support multi platform - float.register_builtin_const("EPSILON", ValueObj::Float(2.220446049250313e-16)); + float.register_builtin_const("EPSILON", Public, ValueObj::Float(2.220446049250313e-16)); float.register_builtin_impl("Real", Float, Const, Public); float.register_builtin_impl("Imag", Float, Const, Public); float.register_marker_trait(builtin_mono("Num")); @@ -516,25 +508,28 @@ impl Context { let op_t = fn1_met(Float, Float, Float); let mut float_add = Self::builtin_methods("Add", 2); float_add.register_builtin_impl("__add__", op_t.clone(), Const, Public); - float_add.register_builtin_const("Output", ValueObj::builtin_t(Float)); + float_add.register_builtin_const("Output", Public, ValueObj::builtin_t(Float)); float.register_trait(Float, builtin_poly("Add", vec![ty_tp(Float)]), float_add); let mut float_sub = Self::builtin_methods("Sub", 2); float_sub.register_builtin_impl("__sub__", op_t.clone(), Const, Public); - float_sub.register_builtin_const("Output", ValueObj::builtin_t(Float)); + float_sub.register_builtin_const("Output", Public, ValueObj::builtin_t(Float)); float.register_trait(Float, builtin_poly("Sub", vec![ty_tp(Float)]), float_sub); let mut float_mul = Self::builtin_methods("Mul", 2); float_mul.register_builtin_impl("__mul__", op_t.clone(), Const, Public); - float_mul.register_builtin_const("Output", ValueObj::builtin_t(Float)); - float_mul.register_builtin_const("PowOutput", ValueObj::builtin_t(Float)); + float_mul.register_builtin_const("Output", Public, ValueObj::builtin_t(Float)); + float_mul.register_builtin_const("PowOutput", Public, ValueObj::builtin_t(Float)); float.register_trait(Float, builtin_poly("Mul", vec![ty_tp(Float)]), float_mul); let mut float_div = Self::builtin_methods("Div", 2); float_div.register_builtin_impl("__div__", op_t, Const, Public); - float_div.register_builtin_const("Output", ValueObj::builtin_t(Float)); - float_div.register_builtin_const("ModOutput", ValueObj::builtin_t(Float)); + float_div.register_builtin_const("Output", Public, ValueObj::builtin_t(Float)); + float_div.register_builtin_const("ModOutput", Public, ValueObj::builtin_t(Float)); float.register_trait(Float, builtin_poly("Div", vec![ty_tp(Float)]), float_div); let mut float_mutizable = Self::builtin_methods("Mutizable", 2); - float_mutizable - .register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Float!"))); + float_mutizable.register_builtin_const( + "MutType!", + Public, + ValueObj::builtin_t(builtin_mono("Float!")), + ); float.register_trait(Float, builtin_mono("Mutizable"), float_mutizable); let mut float_show = Self::builtin_methods("Show", 1); let t = fn0_met(Float, Str); @@ -567,25 +562,28 @@ impl Context { let op_t = fn1_met(Ratio, Ratio, Ratio); let mut ratio_add = Self::builtin_methods("Add", 2); ratio_add.register_builtin_impl("__add__", op_t.clone(), Const, Public); - ratio_add.register_builtin_const("Output", ValueObj::builtin_t(Ratio)); + ratio_add.register_builtin_const("Output", Public, ValueObj::builtin_t(Ratio)); ratio.register_trait(Ratio, builtin_poly("Add", vec![ty_tp(Ratio)]), ratio_add); let mut ratio_sub = Self::builtin_methods("Sub", 2); ratio_sub.register_builtin_impl("__sub__", op_t.clone(), Const, Public); - ratio_sub.register_builtin_const("Output", ValueObj::builtin_t(Ratio)); + ratio_sub.register_builtin_const("Output", Public, ValueObj::builtin_t(Ratio)); ratio.register_trait(Ratio, builtin_poly("Sub", vec![ty_tp(Ratio)]), ratio_sub); let mut ratio_mul = Self::builtin_methods("Mul", 2); ratio_mul.register_builtin_impl("__mul__", op_t.clone(), Const, Public); - ratio_mul.register_builtin_const("Output", ValueObj::builtin_t(Ratio)); - ratio_mul.register_builtin_const("PowOutput", ValueObj::builtin_t(Ratio)); + ratio_mul.register_builtin_const("Output", Public, ValueObj::builtin_t(Ratio)); + ratio_mul.register_builtin_const("PowOutput", Public, ValueObj::builtin_t(Ratio)); ratio.register_trait(Ratio, builtin_poly("Mul", vec![ty_tp(Ratio)]), ratio_mul); let mut ratio_div = Self::builtin_methods("Div", 2); ratio_div.register_builtin_impl("__div__", op_t, Const, Public); - ratio_div.register_builtin_const("Output", ValueObj::builtin_t(Ratio)); - ratio_div.register_builtin_const("ModOutput", ValueObj::builtin_t(Ratio)); + ratio_div.register_builtin_const("Output", Public, ValueObj::builtin_t(Ratio)); + ratio_div.register_builtin_const("ModOutput", Public, ValueObj::builtin_t(Ratio)); ratio.register_trait(Ratio, builtin_poly("Div", vec![ty_tp(Ratio)]), ratio_div); let mut ratio_mutizable = Self::builtin_methods("Mutizable", 2); - ratio_mutizable - .register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Ratio!"))); + ratio_mutizable.register_builtin_const( + "MutType!", + Public, + ValueObj::builtin_t(builtin_mono("Ratio!")), + ); ratio.register_trait(Ratio, builtin_mono("Mutizable"), ratio_mutizable); let mut ratio_show = Self::builtin_methods("Show", 1); let t = fn0_met(Ratio, Str); @@ -620,19 +618,23 @@ impl Context { let op_t = fn1_met(Int, Int, Int); let mut int_add = Self::builtin_methods("Add", 2); int_add.register_builtin_impl("__add__", op_t.clone(), Const, Public); - int_add.register_builtin_const("Output", ValueObj::builtin_t(Int)); + int_add.register_builtin_const("Output", Public, ValueObj::builtin_t(Int)); int.register_trait(Int, builtin_poly("Add", vec![ty_tp(Int)]), int_add); let mut int_sub = Self::builtin_methods("Sub", 2); int_sub.register_builtin_impl("__sub__", op_t.clone(), Const, Public); - int_sub.register_builtin_const("Output", ValueObj::builtin_t(Int)); + int_sub.register_builtin_const("Output", Public, ValueObj::builtin_t(Int)); int.register_trait(Int, builtin_poly("Sub", vec![ty_tp(Int)]), int_sub); let mut int_mul = Self::builtin_methods("Mul", 2); int_mul.register_builtin_impl("__mul__", op_t, Const, Public); - int_mul.register_builtin_const("Output", ValueObj::builtin_t(Int)); - int_mul.register_builtin_const("PowOutput", ValueObj::builtin_t(Nat)); + int_mul.register_builtin_const("Output", Public, ValueObj::builtin_t(Int)); + int_mul.register_builtin_const("PowOutput", Public, ValueObj::builtin_t(Nat)); int.register_trait(Int, builtin_poly("Mul", vec![ty_tp(Int)]), int_mul); let mut int_mutizable = Self::builtin_methods("Mutizable", 2); - int_mutizable.register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Int!"))); + int_mutizable.register_builtin_const( + "MutType!", + Public, + ValueObj::builtin_t(builtin_mono("Int!")), + ); int.register_trait(Int, builtin_mono("Mutizable"), int_mutizable); let mut int_show = Self::builtin_methods("Show", 1); let t = fn0_met(Int, Str); @@ -679,14 +681,18 @@ impl Context { let op_t = fn1_met(Nat, Nat, Nat); let mut nat_add = Self::builtin_methods("Add", 2); nat_add.register_builtin_impl("__add__", op_t.clone(), Const, Public); - nat_add.register_builtin_const("Output", ValueObj::builtin_t(Nat)); + nat_add.register_builtin_const("Output", Public, ValueObj::builtin_t(Nat)); nat.register_trait(Nat, builtin_poly("Add", vec![ty_tp(Nat)]), nat_add); let mut nat_mul = Self::builtin_methods("Mul", 2); nat_mul.register_builtin_impl("__mul__", op_t, Const, Public); - nat_mul.register_builtin_const("Output", ValueObj::builtin_t(Nat)); + nat_mul.register_builtin_const("Output", Public, ValueObj::builtin_t(Nat)); nat.register_trait(Nat, builtin_poly("Mul", vec![ty_tp(Nat)]), nat_mul); let mut nat_mutizable = Self::builtin_methods("Mutizable", 2); - nat_mutizable.register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Nat!"))); + nat_mutizable.register_builtin_const( + "MutType!", + Public, + ValueObj::builtin_t(builtin_mono("Nat!")), + ); nat.register_trait(Nat, builtin_mono("Mutizable"), nat_mutizable); nat.register_builtin_impl("Real", Nat, Const, Public); nat.register_builtin_impl("Imag", Nat, Const, Public); @@ -718,11 +724,14 @@ impl Context { bool_.register_trait(Bool, builtin_poly("Eq", vec![ty_tp(Bool)]), bool_eq); let mut bool_add = Self::builtin_methods("Add", 2); bool_add.register_builtin_impl("__add__", fn1_met(Bool, Bool, Int), Const, Public); - bool_add.register_builtin_const("Output", ValueObj::builtin_t(Nat)); + bool_add.register_builtin_const("Output", Public, ValueObj::builtin_t(Nat)); bool_.register_trait(Bool, builtin_poly("Add", vec![ty_tp(Bool)]), bool_add); let mut bool_mutizable = Self::builtin_methods("Mutizable", 2); - bool_mutizable - .register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Bool!"))); + bool_mutizable.register_builtin_const( + "MutType!", + Public, + ValueObj::builtin_t(builtin_mono("Bool!")), + ); bool_.register_trait(Bool, builtin_mono("Mutizable"), bool_mutizable); let mut bool_show = Self::builtin_methods("Show", 1); bool_show.register_builtin_impl("to_str", fn0_met(Bool, Str), Immutable, Public); @@ -765,14 +774,18 @@ impl Context { str_.register_trait(Str, builtin_poly("Seq", vec![ty_tp(Str)]), str_seq); let mut str_add = Self::builtin_methods("Add", 2); str_add.register_builtin_impl("__add__", fn1_met(Str, Str, Str), Const, Public); - str_add.register_builtin_const("Output", ValueObj::builtin_t(Str)); + str_add.register_builtin_const("Output", Public, ValueObj::builtin_t(Str)); str_.register_trait(Str, builtin_poly("Add", vec![ty_tp(Str)]), str_add); let mut str_mul = Self::builtin_methods("Mul", 2); str_mul.register_builtin_impl("__mul__", fn1_met(Str, Nat, Str), Const, Public); - str_mul.register_builtin_const("Output", ValueObj::builtin_t(Str)); + str_mul.register_builtin_const("Output", Public, ValueObj::builtin_t(Str)); str_.register_trait(Str, builtin_poly("Mul", vec![ty_tp(Nat)]), str_mul); let mut str_mutizable = Self::builtin_methods("Mutizable", 2); - str_mutizable.register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Str!"))); + str_mutizable.register_builtin_const( + "MutType!", + Public, + ValueObj::builtin_t(builtin_mono("Str!")), + ); str_.register_trait(Str, builtin_mono("Mutizable"), str_mutizable); let mut str_show = Self::builtin_methods("Show", 1); str_show.register_builtin_impl("to_str", fn0_met(Str, Str), Immutable, Public); @@ -877,7 +890,19 @@ impl Context { vec![TyParam::t(mono_q("T")), TyParam::mono_q("N").mutate()], )); // [T; N].MutType! = [T; !N] (neither [T!; N] nor [T; N]!) - array_.register_builtin_const("MutType!", mut_type); + array_.register_builtin_const("MutType!", Public, mut_type); + let getitem_t = fn1_kw_met( + builtin_mono("GenericArray"), // TODO: + kw("Index", Nat), + mono_q("T"), + ); + let get_item = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new( + "__getitem__", + __array_getitem__, + getitem_t, + None, + ))); + array_.register_builtin_const("__getitem__", Public, get_item); let mut array_eq = Self::builtin_methods("Eq", 2); array_eq.register_builtin_impl( "__eq__", @@ -932,7 +957,7 @@ impl Context { "Set!", vec![TyParam::t(mono_q("T")), TyParam::mono_q("N").mutate()], )); - set_.register_builtin_const("MutType!", mut_type); + set_.register_builtin_const("MutType!", Public, mut_type); let mut set_eq = Self::builtin_methods("Eq", 2); set_eq.register_builtin_impl( "__eq__", @@ -958,237 +983,79 @@ impl Context { ); set_type.register_superclass(set_t.clone(), &set_); set_type.register_superclass(Type, &type_); + let g_dict_t = builtin_mono("GenericDict"); + let mut generic_dict = Self::builtin_mono_class("GenericDict", 2); + generic_dict.register_superclass(Obj, &obj); + let mut generic_dict_eq = Self::builtin_methods("Eq", 2); + generic_dict_eq.register_builtin_impl( + "__eq__", + fn1_met(g_dict_t.clone(), g_dict_t.clone(), Bool), + Const, + Public, + ); + generic_dict.register_trait( + g_dict_t.clone(), + builtin_poly("Eq", vec![ty_tp(g_dict_t.clone())]), + generic_dict_eq, + ); let dict_t = builtin_poly("Dict", vec![mono_q_tp("D")]); let mut dict_ = // TODO: D <: GenericDict Self::builtin_poly_class("Dict", vec![PS::named_nd("D", builtin_mono("GenericDict"))], 10); - dict_.register_superclass(Obj, &obj); + dict_.register_superclass(g_dict_t.clone(), &generic_dict); dict_.register_marker_trait(builtin_poly("Output", vec![ty_tp(mono_q("D"))])); + let dict_getitem_t = fn1_kw_met( + builtin_mono("GenericDict"), // TODO: + kw("Index", mono_q("K")), + proj_method(mono_q_tp("D"), "__getitem__", vec![mono_q_tp("K")]), + ); + let dict_getitem_t = quant(dict_getitem_t, set! {static_instance("K", Type)}); + let get_item = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new( + "__getitem__", + __dict_getitem__, + dict_getitem_t, + None, + ))); + dict_.register_builtin_const("__getitem__", Public, get_item); /* Bytes */ let mut bytes = Self::builtin_mono_class("Bytes", 2); bytes.register_superclass(Obj, &obj); - // FIXME: replace to Tuple Ts (e.g. Tuple [Int, Str]) - let mut tuple_ = Self::builtin_mono_class("Tuple", 2); - tuple_.register_superclass(Obj, &obj); + let mut generic_tuple = Self::builtin_mono_class("GenericTuple", 1); + generic_tuple.register_superclass(Obj, &obj); let mut tuple_eq = Self::builtin_methods("Eq", 2); tuple_eq.register_builtin_impl( "__eq__", - fn1_met(builtin_mono("Tuple"), builtin_mono("Tuple"), Bool), + fn1_met( + builtin_mono("GenericTuple"), + builtin_mono("GenericTuple"), + Bool, + ), Const, Public, ); - tuple_.register_trait( - builtin_mono("Tuple"), - builtin_poly("Eq", vec![ty_tp(builtin_mono("Tuple"))]), + generic_tuple.register_trait( + builtin_mono("GenericTuple"), + builtin_poly("Eq", vec![ty_tp(builtin_mono("GenericTuple"))]), tuple_eq, ); - let mut tuple1 = Self::builtin_poly_class("Tuple1", vec![PS::t_nd("A")], 2); - tuple1.register_superclass(builtin_mono("Tuple"), &tuple_); - let mut tuple1_eq = Self::builtin_methods("Eq", 2); - tuple1_eq.register_builtin_impl( - "__eq__", - fn1_met( - builtin_poly("Tuple1", vec![ty_tp(mono_q("A"))]), - builtin_poly("Tuple1", vec![ty_tp(mono_q("A"))]), - Bool, - ), - Const, - Public, + // Ts <: GenericArray + let tuple_t = builtin_poly("Tuple", vec![mono_q_tp("Ts")]); + let mut tuple_ = + Self::builtin_poly_class("Tuple", vec![PS::named_nd("Ts", mono_q("Ts"))], 2); + tuple_.register_superclass(builtin_mono("GenericTuple"), &generic_tuple); + tuple_.register_marker_trait(builtin_poly("Output", vec![ty_tp(mono_q("Ts"))])); + // __Tuple_getitem__: (self: Tuple(Ts), _: {N}) -> Ts[N] + let return_t = proj_method(mono_q_tp("Ts"), "__getitem__", vec![mono_q_tp("N")]); + let tuple_getitem_t = fn1_met( + tuple_t.clone(), + tp_enum(Nat, set! {mono_q_tp("N")}), + return_t, ); - tuple1.register_trait( - builtin_poly("Tuple1", vec![ty_tp(mono_q("A"))]), - builtin_poly( - "Eq", - vec![ty_tp(builtin_poly("Tuple1", vec![ty_tp(mono_q("A"))]))], - ), - tuple1_eq, - ); - /* Tuple(n) */ - let mut tuple2 = Self::builtin_poly_class("Tuple2", vec![PS::t_nd("A"), PS::t_nd("B")], 2); - tuple2.register_superclass(builtin_mono("Tuple"), &tuple_); - let mut tuple2_eq = Self::builtin_methods("Eq", 2); - tuple2_eq.register_builtin_impl( - "__eq__", - fn1_met( - builtin_poly("Tuple2", vec![ty_tp(mono_q("A")), ty_tp(mono_q("B"))]), - builtin_poly("Tuple2", vec![ty_tp(mono_q("A")), ty_tp(mono_q("B"))]), - Bool, - ), - Const, - Public, - ); - tuple2.register_trait( - builtin_poly("Tuple2", vec![ty_tp(mono_q("A")), ty_tp(mono_q("B"))]), - builtin_poly( - "Eq", - vec![ty_tp(builtin_poly( - "Tuple2", - vec![ty_tp(mono_q("A")), ty_tp(mono_q("B"))], - ))], - ), - tuple2_eq, - ); - let mut tuple3 = Self::builtin_poly_class( - "Tuple3", - vec![PS::t_nd("A"), PS::t_nd("B"), PS::t_nd("C")], - 2, - ); - tuple3.register_superclass(builtin_mono("Tuple"), &tuple_); - let mut tuple3_eq = Self::builtin_methods("Eq", 2); - tuple3_eq.register_builtin_impl( - "__eq__", - fn1_met( - builtin_poly( - "Tuple3", - vec![ty_tp(mono_q("A")), ty_tp(mono_q("B")), ty_tp(mono_q("C"))], - ), - builtin_poly( - "Tuple3", - vec![ty_tp(mono_q("A")), ty_tp(mono_q("B")), ty_tp(mono_q("C"))], - ), - Bool, - ), - Const, - Public, - ); - tuple3.register_trait( - builtin_poly( - "Tuple3", - vec![ty_tp(mono_q("A")), ty_tp(mono_q("B")), ty_tp(mono_q("C"))], - ), - builtin_poly( - "Eq", - vec![ty_tp(builtin_poly( - "Tuple3", - vec![ty_tp(mono_q("A")), ty_tp(mono_q("B")), ty_tp(mono_q("C"))], - ))], - ), - tuple3_eq, - ); - let mut tuple4 = Self::builtin_poly_class( - "Tuple4", - vec![PS::t_nd("A"), PS::t_nd("B"), PS::t_nd("C"), PS::t_nd("D")], - 2, - ); - tuple4.register_superclass(builtin_mono("Tuple"), &tuple_); - let mut tuple4_eq = Self::builtin_methods("Eq", 2); - tuple4_eq.register_builtin_impl( - "__eq__", - fn1_met( - builtin_poly( - "Tuple4", - vec![ - ty_tp(mono_q("A")), - ty_tp(mono_q("B")), - ty_tp(mono_q("C")), - ty_tp(mono_q("D")), - ], - ), - builtin_poly( - "Tuple4", - vec![ - ty_tp(mono_q("A")), - ty_tp(mono_q("B")), - ty_tp(mono_q("C")), - ty_tp(mono_q("D")), - ], - ), - Bool, - ), - Const, - Public, - ); - tuple4.register_trait( - builtin_poly( - "Tuple4", - vec![ - ty_tp(mono_q("A")), - ty_tp(mono_q("B")), - ty_tp(mono_q("C")), - ty_tp(mono_q("D")), - ], - ), - builtin_poly( - "Eq", - vec![ty_tp(builtin_poly( - "Tuple4", - vec![ - ty_tp(mono_q("A")), - ty_tp(mono_q("B")), - ty_tp(mono_q("C")), - ty_tp(mono_q("D")), - ], - ))], - ), - tuple4_eq, - ); - let mut tuple5 = Self::builtin_poly_class( - "Tuple5", - vec![ - PS::t_nd("A"), - PS::t_nd("B"), - PS::t_nd("C"), - PS::t_nd("D"), - PS::t_nd("E"), - ], - 2, - ); - tuple5.register_superclass(builtin_mono("Tuple"), &tuple_); - let mut tuple5_eq = Self::builtin_methods("Eq", 2); - tuple5_eq.register_builtin_impl( - "__eq__", - fn1_met( - builtin_poly( - "Tuple5", - vec![ - ty_tp(mono_q("A")), - ty_tp(mono_q("B")), - ty_tp(mono_q("C")), - ty_tp(mono_q("D")), - ty_tp(mono_q("E")), - ], - ), - builtin_poly( - "Tuple5", - vec![ - ty_tp(mono_q("A")), - ty_tp(mono_q("B")), - ty_tp(mono_q("C")), - ty_tp(mono_q("D")), - ty_tp(mono_q("E")), - ], - ), - Bool, - ), - Const, - Public, - ); - tuple5.register_trait( - builtin_poly( - "Tuple5", - vec![ - ty_tp(mono_q("A")), - ty_tp(mono_q("B")), - ty_tp(mono_q("C")), - ty_tp(mono_q("D")), - ty_tp(mono_q("E")), - ], - ), - builtin_poly( - "Eq", - vec![ty_tp(builtin_poly( - "Tuple5", - vec![ - ty_tp(mono_q("A")), - ty_tp(mono_q("B")), - ty_tp(mono_q("C")), - ty_tp(mono_q("D")), - ty_tp(mono_q("E")), - ], - ))], - ), - tuple5_eq, + let tuple_getitem_t = quant( + tuple_getitem_t, + set! {static_instance("Ts", array(Type, mono_q_tp("N"))), static_instance("N", Nat)}, ); + tuple_.register_builtin_impl("__Tuple_getitem__", tuple_getitem_t, Const, Public); /* record */ let mut record = Self::builtin_mono_class("Record", 2); record.register_superclass(Obj, &obj); @@ -1203,7 +1070,7 @@ impl Context { let mut float_mut = Self::builtin_mono_class("Float!", 2); float_mut.register_superclass(Float, &float); let mut float_mut_mutable = Self::builtin_methods("Mutable", 2); - float_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Float)); + float_mut_mutable.register_builtin_const("ImmutType", Public, ValueObj::builtin_t(Float)); let f_t = kw("f", func(vec![kw("old", Float)], None, vec![], Float)); let t = pr_met( ref_mut(builtin_mono("Float!"), None), @@ -1222,7 +1089,7 @@ impl Context { let mut ratio_mut = Self::builtin_mono_class("Ratio!", 2); ratio_mut.register_superclass(Ratio, &ratio); let mut ratio_mut_mutable = Self::builtin_methods("Mutable", 2); - ratio_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Ratio)); + ratio_mut_mutable.register_builtin_const("ImmutType", Public, ValueObj::builtin_t(Ratio)); let f_t = kw("f", func(vec![kw("old", Ratio)], None, vec![], Ratio)); let t = pr_met( ref_mut(builtin_mono("Ratio!"), None), @@ -1242,7 +1109,7 @@ impl Context { int_mut.register_superclass(Int, &int); int_mut.register_superclass(builtin_mono("Float!"), &float_mut); let mut int_mut_mutable = Self::builtin_methods("Mutable", 2); - int_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Int)); + int_mut_mutable.register_builtin_const("ImmutType", Public, ValueObj::builtin_t(Int)); let f_t = kw("f", func(vec![kw("old", Int)], None, vec![], Int)); let t = pr_met( ref_mut(builtin_mono("Int!"), None), @@ -1262,7 +1129,7 @@ impl Context { nat_mut.register_superclass(builtin_mono("Int!"), &int_mut); /* Nat_mut */ let mut nat_mut_mutable = Self::builtin_methods("Mutable", 2); - nat_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Nat)); + nat_mut_mutable.register_builtin_const("ImmutType", Public, ValueObj::builtin_t(Nat)); let f_t = kw("f", func(vec![kw("old", Nat)], None, vec![], Nat)); let t = pr_met( ref_mut(builtin_mono("Nat!"), None), @@ -1282,7 +1149,7 @@ impl Context { bool_mut.register_superclass(Bool, &bool_); bool_mut.register_superclass(builtin_mono("Nat!"), &nat_mut); let mut bool_mut_mutable = Self::builtin_methods("Mutable", 2); - bool_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Bool)); + bool_mut_mutable.register_builtin_const("ImmutType", Public, ValueObj::builtin_t(Bool)); let f_t = kw("f", func(vec![kw("old", Bool)], None, vec![], Bool)); let t = pr_met( ref_mut(builtin_mono("Bool!"), None), @@ -1301,7 +1168,7 @@ impl Context { let mut str_mut = Self::builtin_mono_class("Str!", 2); str_mut.register_superclass(Str, &nonetype); let mut str_mut_mutable = Self::builtin_methods("Mutable", 2); - str_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Str)); + str_mut_mutable.register_builtin_const("ImmutType", Public, ValueObj::builtin_t(Str)); let f_t = kw("f", func(vec![kw("old", Str)], None, vec![], Str)); let t = pr_met( ref_mut(builtin_mono("Str!"), None), @@ -1500,31 +1367,11 @@ impl Context { self.register_builtin_type(array_type_t, array_type, Const); self.register_builtin_type(set_t, set_, Const); self.register_builtin_type(set_type_t, set_type, Const); + self.register_builtin_type(g_dict_t, generic_dict, Const); self.register_builtin_type(dict_t, dict_, Const); self.register_builtin_type(builtin_mono("Bytes"), bytes, Const); - self.register_builtin_type(tuple(vec![mono_q("A")]), tuple1, Const); - self.register_builtin_type(tuple(vec![mono_q("A"), mono_q("B")]), tuple2, Const); - self.register_builtin_type( - tuple(vec![mono_q("A"), mono_q("B"), mono_q("C")]), - tuple3, - Const, - ); - self.register_builtin_type( - tuple(vec![mono_q("A"), mono_q("B"), mono_q("C"), mono_q("D")]), - tuple4, - Const, - ); - self.register_builtin_type( - tuple(vec![ - mono_q("A"), - mono_q("B"), - mono_q("C"), - mono_q("D"), - mono_q("E"), - ]), - tuple5, - Const, - ); + self.register_builtin_type(builtin_mono("GenericTuple"), generic_tuple, Const); + self.register_builtin_type(tuple_t, tuple_, Const); self.register_builtin_type(builtin_mono("Record"), record, Const); self.register_builtin_type(builtin_mono("RecordType"), record_type, Const); self.register_builtin_type(or_t, or, Const); @@ -1538,7 +1385,6 @@ impl Context { self.register_builtin_type(array_mut_t, array_mut_, Const); self.register_builtin_type(set_mut_t, set_mut_, Const); self.register_builtin_type(range_t, range, Const); - self.register_builtin_type(builtin_mono("Tuple"), tuple_, Const); self.register_builtin_type(builtin_mono("Proc"), proc, Const); self.register_builtin_type(builtin_mono("NamedProc"), named_proc, Const); self.register_builtin_type(builtin_mono("Func"), func, Const); @@ -1690,7 +1536,7 @@ impl Context { ClassType, ); let class = ConstSubr::Builtin(BuiltinConstSubr::new("Class", class_func, class_t, None)); - self.register_builtin_const("Class", ValueObj::Subr(class)); + self.register_builtin_const("Class", Private, ValueObj::Subr(class)); let inherit_t = func( vec![kw("Super", ClassType)], None, @@ -1703,7 +1549,7 @@ impl Context { inherit_t, None, )); - self.register_builtin_const("Inherit", ValueObj::Subr(inherit)); + self.register_builtin_const("Inherit", Private, ValueObj::Subr(inherit)); let trait_t = func( vec![kw("Requirement", Type)], None, @@ -1711,7 +1557,7 @@ impl Context { TraitType, ); let trait_ = ConstSubr::Builtin(BuiltinConstSubr::new("Trait", trait_func, trait_t, None)); - self.register_builtin_const("Trait", ValueObj::Subr(trait_)); + self.register_builtin_const("Trait", Private, ValueObj::Subr(trait_)); let subsume_t = func( vec![kw("Super", TraitType)], None, @@ -1724,7 +1570,7 @@ impl Context { subsume_t, None, )); - self.register_builtin_const("Subsume", ValueObj::Subr(subsume)); + self.register_builtin_const("Subsume", Private, ValueObj::Subr(subsume)); // decorators let inheritable_t = func1(ClassType, ClassType); let inheritable = ConstSubr::Builtin(BuiltinConstSubr::new( @@ -1733,7 +1579,7 @@ impl Context { inheritable_t, None, )); - self.register_builtin_const("Inheritable", ValueObj::Subr(inheritable)); + self.register_builtin_const("Inheritable", Private, ValueObj::Subr(inheritable)); // TODO: register Del function object let t_del = nd_func(vec![kw("obj", Obj)], None, NoneType); self.register_builtin_impl("Del", t_del, Immutable, Private); @@ -1836,7 +1682,7 @@ impl Context { let op_t = nd_func( vec![kw("lhs", l.clone()), kw("rhs", r.clone())], None, - mono_proj(mono_q("L"), "Output"), + proj(mono_q("L"), "Output"), ); let op_t = quant( op_t, @@ -1846,7 +1692,7 @@ impl Context { }, ); self.register_builtin_impl("__add__", op_t, Const, Private); - let op_t = bin_op(l.clone(), r.clone(), mono_proj(mono_q("L"), "Output")); + let op_t = bin_op(l.clone(), r.clone(), proj(mono_q("L"), "Output")); let op_t = quant( op_t, set! { @@ -1855,7 +1701,7 @@ impl Context { }, ); self.register_builtin_impl("__sub__", op_t, Const, Private); - let op_t = bin_op(l.clone(), r.clone(), mono_proj(mono_q("L"), "Output")); + let op_t = bin_op(l.clone(), r.clone(), proj(mono_q("L"), "Output")); let op_t = quant( op_t, set! { @@ -1864,7 +1710,7 @@ impl Context { }, ); self.register_builtin_impl("__mul__", op_t, Const, Private); - let op_t = bin_op(l.clone(), r.clone(), mono_proj(mono_q("L"), "Output")); + let op_t = bin_op(l.clone(), r.clone(), proj(mono_q("L"), "Output")); let op_t = quant( op_t, set! { @@ -1874,12 +1720,12 @@ impl Context { ); self.register_builtin_impl("__div__", op_t, Const, Private); let m = mono_q("M"); - let op_t = bin_op(m.clone(), m.clone(), mono_proj(m.clone(), "PowOutput")); + let op_t = bin_op(m.clone(), m.clone(), proj(m.clone(), "PowOutput")); let op_t = quant(op_t, set! {subtypeof(m, builtin_poly("Mul", vec![]))}); // TODO: add bound: M == M.Output self.register_builtin_impl("__pow__", op_t, Const, Private); let d = mono_q("D"); - let op_t = bin_op(d.clone(), d.clone(), mono_proj(d.clone(), "ModOutput")); + let op_t = bin_op(d.clone(), d.clone(), proj(d.clone(), "ModOutput")); let op_t = quant(op_t, set! {subtypeof(d, builtin_poly("Div", vec![]))}); self.register_builtin_impl("__mod__", op_t, Const, Private); let e = mono_q("E"); @@ -1917,7 +1763,7 @@ impl Context { self.register_builtin_impl("__in__", op_t, Const, Private); /* unary */ // TODO: Boolの+/-は警告を出したい - let op_t = func1(mono_q("T"), mono_proj(mono_q("T"), "MutType!")); + let op_t = func1(mono_q("T"), proj(mono_q("T"), "MutType!")); let op_t = quant( op_t, set! {subtypeof(mono_q("T"), builtin_mono("Mutizable"))}, @@ -1952,6 +1798,7 @@ impl Context { interval_add.register_builtin_impl("__add__", op_t, Const, Public); interval_add.register_builtin_const( "Output", + Public, ValueObj::builtin_t(Type::from(m.clone() + o.clone()..=n.clone() + p.clone())), ); interval.register_trait( @@ -1968,6 +1815,7 @@ impl Context { interval_sub.register_builtin_impl("__sub__", op_t, Const, Public); interval_sub.register_builtin_const( "Output", + Public, ValueObj::builtin_t(Type::from(m.clone() - p.clone()..=n.clone() - o.clone())), ); interval.register_trait( diff --git a/compiler/erg_compiler/context/inquire.rs b/compiler/erg_compiler/context/inquire.rs index 46f9bd7e..b2eacc2a 100644 --- a/compiler/erg_compiler/context/inquire.rs +++ b/compiler/erg_compiler/context/inquire.rs @@ -17,7 +17,7 @@ use erg_parser::ast::{self, Identifier}; use erg_parser::token::Token; use erg_type::constructors::{ - anon, builtin_mono, builtin_poly, free_var, func, module, mono_proj, subr_t, v_enum, + anon, builtin_mono, builtin_poly, free_var, func, module, proj, subr_t, v_enum, }; use erg_type::free::Constraint; use erg_type::typaram::TyParam; @@ -1864,7 +1864,7 @@ impl Context { // TODO: params, polymorphic types pub(crate) fn get_candidates(&self, t: &Type) -> Option> { match t { - Type::MonoProj { lhs, rhs } => Some(self.get_proj_candidates(lhs, rhs)), + Type::Proj { lhs, rhs } => Some(self.get_proj_candidates(lhs, rhs)), Type::Subr(subr) => { let candidates = self.get_candidates(&subr.return_t)?; Some( @@ -1896,7 +1896,7 @@ impl Context { let candidates = insts.into_iter().filter_map(move |inst| { if self.supertype_of(&inst.sup_trait, &sup) { self.eval_t_params( - mono_proj(inst.sub_type, rhs), + proj(inst.sub_type, rhs), self.level, Location::Unknown, ) @@ -1920,7 +1920,7 @@ impl Context { Type::FreeVar(fv) if fv.is_linked() => self.is_class(&fv.crack()), Type::FreeVar(_) => false, Type::Or(l, r) => self.is_class(l) && self.is_class(r), - Type::MonoProj { lhs, rhs } => self + Type::Proj { lhs, rhs } => self .get_proj_candidates(lhs, rhs) .iter() .all(|t| self.is_class(t)), @@ -1943,7 +1943,7 @@ impl Context { Type::FreeVar(fv) if fv.is_linked() => self.is_class(&fv.crack()), Type::FreeVar(_) => false, Type::And(l, r) | Type::Or(l, r) => self.is_trait(l) && self.is_trait(r), - Type::MonoProj { lhs, rhs } => self + Type::Proj { lhs, rhs } => self .get_proj_candidates(lhs, rhs) .iter() .all(|t| self.is_trait(t)), diff --git a/compiler/erg_compiler/context/instantiate.rs b/compiler/erg_compiler/context/instantiate.rs index b0e41032..65199fbf 100644 --- a/compiler/erg_compiler/context/instantiate.rs +++ b/compiler/erg_compiler/context/instantiate.rs @@ -159,13 +159,13 @@ impl TyVarContext { Type::BuiltinPoly { name, params } => { self.instantiate_poly(None, mid.name(), &name, params, ctx) } - Type::MonoProj { lhs, rhs } => { + Type::Proj { lhs, rhs } => { let lhs = if lhs.has_qvar() { self.instantiate_qvar(*lhs) } else { *lhs }; - mono_proj(lhs, rhs) + proj(lhs, rhs) } Type::Ref(t) if t.has_qvar() => ref_(self.instantiate_qvar(*t)), Type::RefMut { before, after } => { @@ -242,6 +242,7 @@ impl TyVarContext { } TyBound::Instance { name, t } => { let t = match t { + Type::FreeVar(fv) if fv.is_linked() => todo!(), Type::BuiltinPoly { name, params } => { self.instantiate_poly(None, name.clone(), &name, params, ctx) } @@ -251,8 +252,7 @@ impl TyVarContext { t => t, }; let constraint = Constraint::new_type_of(t.clone()); - // TODO: type-like types - if t == Type { + if t.is_type() { if let Some(tv) = self.tyvar_instances.get(&name) { tv.update_constraint(constraint); } else if let Some(tp) = self.typaram_instances.get(&name) { @@ -438,7 +438,10 @@ impl TyVarContext { pub(crate) fn push_or_init_typaram(&mut self, name: &Str, tp: &TyParam) { // FIXME: - if self.tyvar_instances.get(name).is_some() || self.typaram_instances.get(name).is_some() { + if let Some(_tp) = self.typaram_instances.get(name) { + return; + } + if let Some(_t) = self.tyvar_instances.get(name) { return; } self.typaram_instances.insert(name.clone(), tp.clone()); @@ -1053,9 +1056,20 @@ impl Context { .transpose()?; Ok(ref_mut(before, after)) } - MonoProj { lhs, rhs } => { + Proj { lhs, rhs } => { let lhs = self.instantiate_t(*lhs, tmp_tv_ctx, loc)?; - Ok(mono_proj(lhs, rhs)) + Ok(proj(lhs, rhs)) + } + ProjMethod { + lhs, + method_name, + mut args, + } => { + let lhs = self.instantiate_tp(*lhs, tmp_tv_ctx, loc)?; + for arg in args.iter_mut() { + *arg = self.instantiate_tp(mem::take(arg), tmp_tv_ctx, loc)?; + } + Ok(proj_method(lhs, method_name, args)) } BuiltinPoly { name, mut params } => { for param in params.iter_mut() { diff --git a/compiler/erg_compiler/context/mod.rs b/compiler/erg_compiler/context/mod.rs index 39451fd5..6b9ecf99 100644 --- a/compiler/erg_compiler/context/mod.rs +++ b/compiler/erg_compiler/context/mod.rs @@ -870,6 +870,15 @@ impl Context { log!(info "{}: current namespace: {}", fn_name!(), self.name); ctx } else { + panic!("cannot pop the top-level context (or use `pop_mod`)"); + } + } + + pub fn pop_mod(&mut self) -> Context { + if self.outer.is_some() { + panic!("not in the top-level context"); + } else { + log!(info "{}: current namespace: ", fn_name!()); // toplevel mem::take(self) } diff --git a/compiler/erg_compiler/context/register.rs b/compiler/erg_compiler/context/register.rs index 5067af8e..6f04b575 100644 --- a/compiler/erg_compiler/context/register.rs +++ b/compiler/erg_compiler/context/register.rs @@ -938,11 +938,11 @@ impl Context { HIRBuilder::new_with_cache(cfg, __name__, mod_cache.clone(), py_mod_cache.clone()); match builder.build(src, "exec") { Ok(hir) => { - mod_cache.register(path.clone(), Some(hir), builder.pop_ctx()); + mod_cache.register(path.clone(), Some(hir), builder.pop_mod_ctx()); } Err((maybe_hir, errs)) => { if let Some(hir) = maybe_hir { - mod_cache.register(path, Some(hir), builder.pop_ctx()); + mod_cache.register(path, Some(hir), builder.pop_mod_ctx()); } return Err(errs); } @@ -1037,11 +1037,11 @@ impl Context { HIRBuilder::new_with_cache(cfg, __name__, py_mod_cache.clone(), py_mod_cache.clone()); match builder.build(src, "declare") { Ok(hir) => { - py_mod_cache.register(path.clone(), Some(hir), builder.pop_ctx()); + py_mod_cache.register(path.clone(), Some(hir), builder.pop_mod_ctx()); } Err((maybe_hir, errs)) => { if let Some(hir) = maybe_hir { - py_mod_cache.register(path, Some(hir), builder.pop_ctx()); + py_mod_cache.register(path, Some(hir), builder.pop_mod_ctx()); } return Err(errs); } diff --git a/compiler/erg_compiler/context/tyvar.rs b/compiler/erg_compiler/context/tyvar.rs index 66781aa6..f1629201 100644 --- a/compiler/erg_compiler/context/tyvar.rs +++ b/compiler/erg_compiler/context/tyvar.rs @@ -195,9 +195,20 @@ impl Context { .collect::>(); poly(path, name, params) } - MonoProj { lhs, rhs } => { + Proj { lhs, rhs } => { let lhs = self.generalize_t_inner(*lhs, bounds, lazy_inits); - mono_proj(lhs, rhs) + proj(lhs, rhs) + } + ProjMethod { + lhs, + method_name, + mut args, + } => { + let lhs = self.generalize_tp(*lhs, bounds, lazy_inits); + for arg in args.iter_mut() { + *arg = self.generalize_tp(mem::take(arg), bounds, lazy_inits); + } + proj_method(lhs, method_name, args) } And(l, r) => { let l = self.generalize_t_inner(*l, bounds, lazy_inits); @@ -249,7 +260,7 @@ impl Context { } } - fn deref_tp( + pub(crate) fn deref_tp( &self, tp: TyParam, variance: Variance, @@ -274,8 +285,21 @@ impl Context { } TyParam::BinOp { .. } => todo!(), TyParam::UnaryOp { .. } => todo!(), - TyParam::Array(_) | TyParam::Tuple(_) => todo!(), - TyParam::MonoProj { .. } + TyParam::Array(tps) => { + let mut new_tps = vec![]; + for tp in tps { + new_tps.push(self.deref_tp(tp, variance, loc)?); + } + Ok(TyParam::Array(new_tps)) + } + TyParam::Tuple(tps) => { + let mut new_tps = vec![]; + for tp in tps { + new_tps.push(self.deref_tp(tp, variance, loc)?); + } + Ok(TyParam::Tuple(new_tps)) + } + TyParam::Proj { .. } | TyParam::MonoQVar(_) | TyParam::PolyQVar { .. } | TyParam::Failure @@ -617,6 +641,16 @@ impl Context { } } + pub(crate) fn coerce_tp(&self, tp: &TyParam) { + match tp { + TyParam::FreeVar(fv) if fv.is_linked() => { + self.coerce_tp(&fv.crack()); + } + TyParam::Type(t) => self.coerce(t), + _ => {} + } + } + /// Check if all types are resolvable (if traits, check if an implementation exists) /// And replace them if resolvable pub(crate) fn resolve( @@ -1080,7 +1114,7 @@ impl Context { } /// predは正規化されているとする - fn _sub_unify_pred( + fn sub_unify_pred( &self, l_pred: &Predicate, r_pred: &Predicate, @@ -1098,8 +1132,8 @@ impl Context { | (Pred::Or(l1, r1), Pred::Or(l2, r2)) | (Pred::Not(l1, r1), Pred::Not(l2, r2)) => { match ( - self._sub_unify_pred(l1, l2, loc), - self._sub_unify_pred(r1, r2, loc), + self.sub_unify_pred(l1, l2, loc), + self.sub_unify_pred(r1, r2, loc), ) { (Ok(()), Ok(())) => Ok(()), (Ok(()), Err(e)) | (Err(e), Ok(())) | (Err(e), Err(_)) => Err(e), @@ -1304,6 +1338,7 @@ impl Context { return Ok(()); } if !maybe_sub_is_sub { + log!(err "{maybe_sub} !<: {maybe_sup}"); return Err(TyCheckErrors::from(TyCheckError::type_mismatch_error( self.cfg.input.clone(), line!() as usize, @@ -1545,9 +1580,19 @@ impl Context { self.sub_unify(maybe_sub, before, loc, param_name)?; Ok(()) } - (Type::MonoProj { .. }, _) => todo!(), - (_, Type::MonoProj { .. }) => todo!(), - (Refinement(_), Refinement(_)) => todo!(), + (Type::Proj { .. }, _) => todo!(), + (_, Type::Proj { .. }) => todo!(), + (Refinement(l), Refinement(r)) => { + log!(err "{l}, {r}"); + if l.preds.len() == 1 && r.preds.len() == 1 { + let l_first = l.preds.iter().next().unwrap(); + let r_first = r.preds.iter().next().unwrap(); + self.sub_unify_pred(l_first, r_first, loc)?; + log!("{l}, {r}"); + return Ok(()); + } + todo!("{l}, {r}") + }, (Type::Subr(_) | Type::Record(_), Type) => Ok(()), // TODO Tuple2, ... (Type::BuiltinPoly{ name, .. }, Type) if &name[..] == "Array" || &name[..] == "Tuple" => Ok(()), diff --git a/compiler/erg_compiler/lower.rs b/compiler/erg_compiler/lower.rs index 2e014f41..19693cd0 100644 --- a/compiler/erg_compiler/lower.rs +++ b/compiler/erg_compiler/lower.rs @@ -735,7 +735,6 @@ impl ASTLowerer { }, _ => { if let Some(type_spec) = opt_cast_to { - log!(err "cast({type_spec}): {call}"); self.ctx.cast(type_spec, &mut call)?; } } @@ -898,43 +897,54 @@ impl ASTLowerer { if let Err(errs) = self.ctx.preregister(&body.block) { self.errs.extend(errs.into_iter()); } - let block = self.lower_block(body.block).map_err(|e| { - self.pop_append_errs(); - e - })?; - let found_body_t = block.ref_t(); - let opt_expect_body_t = self - .ctx - .outer - .as_ref() - .unwrap() - .get_current_scope_var(sig.inspect().unwrap()) - .map(|vi| vi.t.clone()); - let ident = match &sig.pat { - ast::VarPattern::Ident(ident) => ident, - _ => unreachable!(), - }; - if let Some(expect_body_t) = opt_expect_body_t { - // TODO: expect_body_t is smaller for constants - // TODO: 定数の場合、expect_body_tのほうが小さくなってしまう - if !sig.is_const() { - if let Err(e) = - self.return_t_check(sig.loc(), ident.inspect(), &expect_body_t, found_body_t) - { - self.errs.push(e); + match self.lower_block(body.block) { + Ok(block) => { + let found_body_t = block.ref_t(); + let opt_expect_body_t = self + .ctx + .outer + .as_ref() + .unwrap() + .get_current_scope_var(sig.inspect().unwrap()) + .map(|vi| vi.t.clone()); + let ident = match &sig.pat { + ast::VarPattern::Ident(ident) => ident, + _ => unreachable!(), + }; + if let Some(expect_body_t) = opt_expect_body_t { + // TODO: expect_body_t is smaller for constants + // TODO: 定数の場合、expect_body_tのほうが小さくなってしまう + if !sig.is_const() { + if let Err(e) = self.return_t_check( + sig.loc(), + ident.inspect(), + &expect_body_t, + found_body_t, + ) { + self.errs.push(e); + } + } } + let id = body.id; + self.ctx + .outer + .as_mut() + .unwrap() + .assign_var_sig(&sig, found_body_t, id)?; + let ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone()); + let sig = hir::VarSignature::new(ident, found_body_t.clone()); + let body = hir::DefBody::new(body.op, block, body.id); + Ok(hir::Def::new(hir::Signature::Var(sig), body)) + } + Err(errs) => { + self.ctx.outer.as_mut().unwrap().assign_var_sig( + &sig, + &Type::Never, + ast::DefId(0), + )?; + Err(errs) } } - let id = body.id; - self.ctx - .outer - .as_mut() - .unwrap() - .assign_var_sig(&sig, found_body_t, id)?; - let ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone()); - let sig = hir::VarSignature::new(ident, found_body_t.clone()); - let body = hir::DefBody::new(body.op, block, body.id); - Ok(hir::Def::new(hir::Signature::Var(sig), body)) } // NOTE: 呼ばれている間はinner scopeなので注意 @@ -960,33 +970,41 @@ impl ASTLowerer { if let Err(errs) = self.ctx.preregister(&body.block) { self.errs.extend(errs.into_iter()); } - let block = self.lower_block(body.block).map_err(|e| { - self.pop_append_errs(); - e - })?; - let found_body_t = block.ref_t(); - let expect_body_t = t.return_t.as_ref(); - if !sig.is_const() { - if let Err(e) = self.return_t_check( - sig.loc(), - sig.ident.inspect(), - expect_body_t, - found_body_t, - ) { - self.errs.push(e); + match self.lower_block(body.block) { + Ok(block) => { + let found_body_t = block.ref_t(); + let expect_body_t = t.return_t.as_ref(); + if !sig.is_const() { + if let Err(e) = self.return_t_check( + sig.loc(), + sig.ident.inspect(), + expect_body_t, + found_body_t, + ) { + self.errs.push(e); + } + } + let id = body.id; + let t = + self.ctx + .outer + .as_mut() + .unwrap() + .assign_subr(&sig, id, found_body_t)?; + let ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name); + let sig = hir::SubrSignature::new(ident, sig.params, t); + let body = hir::DefBody::new(body.op, block, body.id); + Ok(hir::Def::new(hir::Signature::Subr(sig), body)) + } + Err(errs) => { + self.ctx.outer.as_mut().unwrap().assign_subr( + &sig, + ast::DefId(0), + &Type::Failure, + )?; + Err(errs) } } - let id = body.id; - let t = self - .ctx - .outer - .as_mut() - .unwrap() - .assign_subr(&sig, id, found_body_t)?; - let ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name); - let sig = hir::SubrSignature::new(ident, sig.params, t); - let body = hir::DefBody::new(body.op, block, body.id); - Ok(hir::Def::new(hir::Signature::Subr(sig), body)) } Type::Failure => { if let Err(errs) = self.ctx.assign_params(&sig.params, None) { @@ -995,15 +1013,12 @@ impl ASTLowerer { if let Err(errs) = self.ctx.preregister(&body.block) { self.errs.extend(errs.into_iter()); } - let block = self.lower_block(body.block).map_err(|e| { - self.pop_append_errs(); - e - })?; self.ctx .outer .as_mut() .unwrap() - .fake_subr_assign(&sig, Type::Failure); + .fake_subr_assign(&sig, Type::Never); + let block = self.lower_block(body.block)?; let ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name); let sig = hir::SubrSignature::new(ident, sig.params, Type::Failure); let body = hir::DefBody::new(body.op, block, body.id); diff --git a/compiler/erg_parser/ast.rs b/compiler/erg_parser/ast.rs index e3222509..9321a552 100644 --- a/compiler/erg_parser/ast.rs +++ b/compiler/erg_parser/ast.rs @@ -145,6 +145,7 @@ impl Locational for Args { if let Some((l, r)) = &self.paren { Location::concat(l, r) } else { + // TODO: kw, var_args Location::concat(&self.pos_args[0], self.pos_args.last().unwrap()) } } @@ -306,6 +307,7 @@ impl TupleAttribute { pub struct Subscript { pub obj: Box, pub index: Box, + pub r_sqbr: Token, } impl NestedDisplay for Subscript { @@ -319,13 +321,14 @@ impl NestedDisplay for Subscript { } impl_display_from_nested!(Subscript); -impl_locational!(Subscript, obj, index); +impl_locational!(Subscript, obj, r_sqbr); impl Subscript { - pub fn new(obj: Expr, index: Expr) -> Self { + pub fn new(obj: Expr, index: Expr, r_sqbr: Token) -> Self { Self { obj: Box::new(obj), index: Box::new(index), + r_sqbr, } } } @@ -415,8 +418,8 @@ impl Accessor { Self::TupleAttr(TupleAttribute::new(obj, index)) } - pub fn subscr(obj: Expr, index: Expr) -> Self { - Self::Subscr(Subscript::new(obj, index)) + pub fn subscr(obj: Expr, index: Expr, r_sqbr: Token) -> Self { + Self::Subscr(Subscript::new(obj, index, r_sqbr)) } pub const fn name(&self) -> Option<&Str> { @@ -944,11 +947,7 @@ impl_display_from_nested!(Call); impl Locational for Call { fn loc(&self) -> Location { - if self.args.is_empty() { - self.obj.loc() - } else { - Location::concat(self.obj.as_ref(), &self.args) - } + Location::concat(self.obj.as_ref(), &self.args) } } diff --git a/compiler/erg_parser/desugar.rs b/compiler/erg_parser/desugar.rs index 9646adee..9f913884 100644 --- a/compiler/erg_parser/desugar.rs +++ b/compiler/erg_parser/desugar.rs @@ -52,6 +52,7 @@ impl Desugarer { let module = self.desugar_multiple_pattern_def(module); let module = self.desugar_pattern(module); let module = Self::desugar_shortened_record(module); + let module = Self::desugar_acc(module); log!(info "AST (desugared):\n{module}"); log!(info "the desugaring process has completed."); module @@ -442,7 +443,17 @@ impl Desugarer { Accessor::tuple_attr(obj, Literal::nat(n, sig.ln_begin().unwrap())) } BufIndex::Array(n) => { - Accessor::subscr(obj, Expr::Lit(Literal::nat(n, sig.ln_begin().unwrap()))) + let r_brace = Token::new( + TokenKind::RBrace, + "]", + sig.ln_begin().unwrap(), + sig.col_begin().unwrap(), + ); + Accessor::subscr( + obj, + Expr::Lit(Literal::nat(n, sig.ln_begin().unwrap())), + r_brace, + ) } BufIndex::Record(attr) => Accessor::attr(obj, attr.clone()), }; @@ -584,13 +595,61 @@ impl Desugarer { fn desugar_acc(mut module: Module) -> Module { let mut new = Module::with_capacity(module.len()); while let Some(chunk) = module.lpop() { - new.push(Self::desugar_acc_inner(chunk)); + new.push(Self::rec_desugar_acc(chunk)); } new } - fn desugar_acc_inner(_expr: Expr) -> Expr { - todo!() + fn rec_desugar_acc(expr: Expr) -> Expr { + match expr { + Expr::Accessor(acc) => Self::desugar_acc_inner(acc), + expr => Self::perform_desugar(Self::rec_desugar_acc, expr), + } + } + + fn desugar_acc_inner(acc: Accessor) -> Expr { + match acc { + // x[y] => x.__getitem__(y) + Accessor::Subscr(subscr) => { + let args = Args::new(vec![PosArg::new(*subscr.index)], vec![], None); + let line = subscr.obj.ln_begin().unwrap(); + let call = Call::new( + Self::rec_desugar_acc(*subscr.obj), + Some(Identifier::public_with_line( + Token::dummy(), + Str::ever("__getitem__"), + line, + )), + args, + ); + Expr::Call(call) + } + // x.0 => x.__Tuple_getitem__(0) + Accessor::TupleAttr(tattr) => { + let args = Args::new(vec![PosArg::new(Expr::Lit(tattr.index))], vec![], None); + let line = tattr.obj.ln_begin().unwrap(); + let call = Call::new( + Self::rec_desugar_acc(*tattr.obj), + Some(Identifier::public_with_line( + Token::dummy(), + Str::ever("__Tuple_getitem__"), + line, + )), + args, + ); + Expr::Call(call) + } + Accessor::TypeApp(mut tapp) => { + tapp.obj = Box::new(Self::rec_desugar_acc(*tapp.obj)); + // REVIEW: tapp.type_args + Expr::Accessor(Accessor::TypeApp(tapp)) + } + Accessor::Attr(mut attr) => { + attr.obj = Box::new(Self::rec_desugar_acc(*attr.obj)); + Expr::Accessor(Accessor::Attr(attr)) + } + other => Expr::Accessor(other), + } } } diff --git a/compiler/erg_parser/parse.rs b/compiler/erg_parser/parse.rs index fd9dd01f..e7fd4969 100644 --- a/compiler/erg_parser/parse.rs +++ b/compiler/erg_parser/parse.rs @@ -10,10 +10,12 @@ use erg_common::config::Input; use erg_common::error::Location; use erg_common::option_enum_unwrap; use erg_common::set::Set as HashSet; +use erg_common::str::Str; use erg_common::traits::Runnable; use erg_common::traits::{Locational, Stream}; use erg_common::{ - caused_by, debug_power_assert, enum_unwrap, fn_name, log, set, switch_lang, switch_unreachable, + caused_by, debug_power_assert, enum_unwrap, fn_name, impl_locational_for_enum, log, set, + switch_lang, switch_unreachable, }; use crate::ast::*; @@ -65,6 +67,8 @@ pub enum BraceContainer { Record(Record), } +impl_locational_for_enum!(BraceContainer; Set, Dict, Record); + /// Perform recursive descent parsing. /// /// `level` is raised by 1 by `debug_call_info!` in each analysis method and lowered by 1 when leaving (`.map_err` is called to lower the level). @@ -391,9 +395,9 @@ impl Parser { } } - fn try_reduce_acc(&mut self, in_type_args: bool) -> ParseResult { + fn try_reduce_acc_lhs(&mut self) -> ParseResult { debug_call_info!(self); - let mut acc = match self.peek() { + let acc = match self.peek() { Some(t) if t.is(Symbol) || t.is(UBar) => Accessor::local(self.lpop()), Some(t) if t.is(Dot) => { let dot = self.lpop(); @@ -414,99 +418,6 @@ impl Parser { return Err(()); } }; - loop { - match self.peek() { - Some(t) if t.is(Dot) => { - let vis = self.lpop(); - let token = self.lpop(); - match token.kind { - Symbol => { - let ident = Identifier::new(Some(vis), VarName::new(token)); - acc = Accessor::attr(Expr::Accessor(acc), ident); - } - NatLit => { - let attr = Literal::from(token); - acc = Accessor::tuple_attr(Expr::Accessor(acc), attr); - } - Newline => { - self.restore(token); - self.restore(vis); - break; - } - _ => { - self.restore(token); - self.level -= 1; - let err = self.skip_and_throw_syntax_err(caused_by!()); - self.errs.push(err); - return Err(()); - } - } - } - Some(t) if t.is(DblColon) => { - let vis = self.lpop(); - let token = self.lpop(); - match token.kind { - Symbol => { - let ident = Identifier::new(None, VarName::new(token)); - acc = Accessor::attr(Expr::Accessor(acc), ident); - } - // DataPack - LBrace => { - self.restore(token); - self.restore(vis); - break; - } - // MethodDefs - Newline => { - self.restore(token); - self.restore(vis); - break; - } - _ => { - self.restore(token); - self.level -= 1; - let err = self.skip_and_throw_syntax_err(caused_by!()); - self.errs.push(err); - return Err(()); - } - } - } - // x[...] (`x [...]` will interpreted as `x([...])`) - Some(t) if t.is(LSqBr) && acc.col_end().unwrap() == t.col_begin().unwrap() => { - self.skip(); - let index = self - .try_reduce_expr(false, false, false) - .map_err(|_| self.stack_dec())?; - if self.cur_is(RSqBr) { - self.skip(); - } else { - self.level -= 1; - let err = self.skip_and_throw_syntax_err(caused_by!()); - self.errs.push(err); - return Err(()); - } - acc = Accessor::subscr(Expr::Accessor(acc), index); - if self.cur_is(RSqBr) { - self.lpop(); - } else { - self.level -= 1; - // TODO: error report: RSqBr not found - let err = self.skip_and_throw_syntax_err(caused_by!()); - self.errs.push(err); - return Err(()); - } - } - Some(t) if t.is(VBar) && !in_type_args => { - let type_args = self - .try_reduce_type_app_args() - .map_err(|_| self.stack_dec())?; - acc = Accessor::TypeApp(TypeApp::new(Expr::Accessor(acc), type_args)); - } - _ => { - break; - } - } - } self.level -= 1; Ok(acc) } @@ -755,9 +666,7 @@ impl Parser { return Ok(PosOrKwArg::Pos(PosArg::new(Expr::Lambda(lambda)))); } if self.nth_is(1, Walrus) { - let acc = self - .try_reduce_acc(in_type_args) - .map_err(|_| self.stack_dec())?; + let acc = self.try_reduce_acc_lhs().map_err(|_| self.stack_dec())?; // TODO: type specification debug_power_assert!(self.cur_is(Walrus)); self.skip(); @@ -799,9 +708,7 @@ impl Parser { match self.peek() { Some(t) if t.is(Symbol) => { if self.nth_is(1, Walrus) { - let acc = self - .try_reduce_acc(in_type_args) - .map_err(|_| self.stack_dec())?; + let acc = self.try_reduce_acc_lhs().map_err(|_| self.stack_dec())?; debug_power_assert!(self.cur_is(Walrus)); self.skip(); let keyword = if let Accessor::Ident(n) = acc { @@ -1473,30 +1380,144 @@ impl Parser { #[inline] fn try_reduce_call_or_acc(&mut self, in_type_args: bool) -> ParseResult { debug_call_info!(self); - let acc = self - .try_reduce_acc(in_type_args) - .map_err(|_| self.stack_dec())?; - if let Some(res) = self.opt_reduce_args(in_type_args) { + let acc = self.try_reduce_acc_lhs().map_err(|_| self.stack_dec())?; + let mut call_or_acc = self.try_reduce_acc_chain(acc, in_type_args)?; + while let Some(res) = self.opt_reduce_args(in_type_args) { let args = res.map_err(|_| self.stack_dec())?; - let (obj, method_name) = match acc { - Accessor::Attr(attr) => (*attr.obj, Some(attr.ident)), - other => (Expr::Accessor(other), None), + let (receiver, method_name) = match call_or_acc { + Expr::Accessor(Accessor::Attr(attr)) => (*attr.obj, Some(attr.ident)), + other => (other, None), }; - let mut call = Expr::Call(Call::new(obj, method_name, args)); - // e.g. - // f(x).y == Attr { obj: f(x) attr: .y } - // f(x) .y == Call { obj: f(x), args: [.y] } (with warning) - // f(x) g(x) == f(x)(g(x)) - while let Some(res) = self.opt_reduce_args(in_type_args) { - let args = res.map_err(|_| self.stack_dec())?; - call = Expr::Call(Call::new(call, None, args)); - } - self.level -= 1; - Ok(call) - } else { - self.level -= 1; - Ok(Expr::Accessor(acc)) + let call = Call::new(receiver, method_name, args); + call_or_acc = Expr::Call(call); } + self.level -= 1; + Ok(call_or_acc) + } + + /// [y], .0, .attr, .method(...), (...) + #[inline] + fn try_reduce_acc_chain(&mut self, acc: Accessor, in_type_args: bool) -> ParseResult { + debug_call_info!(self); + let mut obj = Expr::Accessor(acc); + loop { + match self.peek() { + Some(t) if t.is(LSqBr) && obj.col_end() == t.col_begin() => { + let _l_sqbr = self.lpop(); + let index = self + .try_reduce_expr(true, false, false) + .map_err(|_| self.stack_dec())?; + let r_sqbr = if self.cur_is(RSqBr) { + self.lpop() + } else { + self.level -= 1; + // TODO: error report: RSqBr not found + let err = self.skip_and_throw_syntax_err(caused_by!()); + self.errs.push(err); + return Err(()); + }; + obj = Expr::Accessor(Accessor::subscr(obj, index, r_sqbr)); + } + Some(t) if t.is(Dot) && obj.col_end() == t.col_begin() => { + let vis = self.lpop(); + let token = self.lpop(); + match token.kind { + Symbol => { + let ident = Identifier::new(Some(vis), VarName::new(token)); + obj = Expr::Accessor(Accessor::attr(obj, ident)); + } + NatLit => { + let index = Literal::from(token); + obj = Expr::Accessor(Accessor::tuple_attr(obj, index)); + } + Newline => { + self.restore(token); + self.restore(vis); + break; + } + _ => { + self.restore(token); + self.level -= 1; + let err = self.skip_and_throw_syntax_err(caused_by!()); + self.errs.push(err); + return Err(()); + } + } + } + // e.g. l[0].0 + Some(t) if t.is(RatioLit) && obj.col_end() == t.col_begin() => { + let mut token = self.lpop(); + token.content = Str::rc(&token.content[1..]); + token.kind = NatLit; + token.col_begin += 1; + let index = Literal::from(token); + obj = Expr::Accessor(Accessor::tuple_attr(obj, index)); + } + Some(t) if t.is(DblColon) && obj.col_end() == t.col_begin() => { + let vis = self.lpop(); + let token = self.lpop(); + match token.kind { + Symbol => { + let ident = Identifier::new(None, VarName::new(token)); + obj = Expr::Accessor(Accessor::attr(obj, ident)); + } + LBrace => { + self.restore(token); + let args = self + .try_reduce_brace_container() + .map_err(|_| self.stack_dec())?; + match args { + BraceContainer::Record(args) => { + obj = Expr::DataPack(DataPack::new(obj, vis, args)); + } + other => { + self.level -= 1; + let err = ParseError::simple_syntax_error( + line!() as usize, + other.loc(), + ); + self.errs.push(err); + return Err(()); + } + } + } + // MethodDefs + Newline => { + self.restore(token); + self.restore(vis); + break; + } + _ => { + self.restore(token); + self.level -= 1; + let err = self.skip_and_throw_syntax_err(caused_by!()); + self.errs.push(err); + return Err(()); + } + } + } + Some(t) if t.is(LParen) && obj.col_end() == t.col_begin() => { + let args = self.try_reduce_args(false).map_err(|_| self.stack_dec())?; + let (receiver, method_name) = match obj { + Expr::Accessor(Accessor::Attr(attr)) => (*attr.obj, Some(attr.ident)), + other => (other, None), + }; + let call = Call::new(receiver, method_name, args); + obj = Expr::Call(call); + } + Some(t) if t.is(VBar) && !in_type_args => { + let type_args = self + .try_reduce_type_app_args() + .map_err(|_| self.stack_dec())?; + obj = Expr::Accessor(Accessor::TypeApp(TypeApp::new(obj, type_args))); + } + _ => { + break; + } + } + } + self.level -= 1; + Ok(obj) } #[inline] @@ -1754,7 +1775,7 @@ impl Parser { return Ok(ShortenedRecord::new(l_brace, r_brace, idents)); } Some(_) => { - let acc = self.try_reduce_acc(false).map_err(|_| self.stack_dec())?; + let acc = self.try_reduce_acc_lhs().map_err(|_| self.stack_dec())?; let acc = match acc { Accessor::Ident(ident) => ident, other => { diff --git a/compiler/erg_type/constructors.rs b/compiler/erg_type/constructors.rs index 31ce967e..325d8051 100644 --- a/compiler/erg_type/constructors.rs +++ b/compiler/erg_type/constructors.rs @@ -35,10 +35,11 @@ pub fn array_mut(elem_t: Type, len: TyParam) -> Type { builtin_poly("Array!", vec![TyParam::t(elem_t), len]) } -// FIXME pub fn tuple(args: Vec) -> Type { - let name = format!("Tuple{}", args.len()); - builtin_poly(name, args.into_iter().map(TyParam::t).collect()) + builtin_poly( + "Tuple", + vec![TyParam::Array(args.into_iter().map(TyParam::t).collect())], + ) } pub fn set_t(elem_t: Type, len: TyParam) -> Type { @@ -280,6 +281,10 @@ pub fn fn1_met(self_t: Type, input_t: Type, return_t: Type) -> Type { ) } +pub fn fn1_kw_met(self_t: Type, input: ParamTy, return_t: Type) -> Type { + fn_met(self_t, vec![input], None, vec![], return_t) +} + pub fn pr_met( self_t: Type, mut non_default_params: Vec, @@ -383,13 +388,22 @@ pub fn poly, T: Into>(path: P, name: T, params: Vec>(lhs: Type, rhs: S) -> Type { - Type::MonoProj { +pub fn proj>(lhs: Type, rhs: S) -> Type { + Type::Proj { lhs: Box::new(lhs), rhs: rhs.into(), } } +#[inline] +pub fn proj_method>(lhs: TyParam, method_name: S, args: Vec) -> Type { + Type::ProjMethod { + lhs: Box::new(lhs), + method_name: method_name.into(), + args, + } +} + /// ```rust /// {I: Int | I >= 0} /// => Refinement{ diff --git a/compiler/erg_type/lib.rs b/compiler/erg_type/lib.rs index d343bd88..72eb1f48 100644 --- a/compiler/erg_type/lib.rs +++ b/compiler/erg_type/lib.rs @@ -1171,10 +1171,15 @@ pub enum Type { name: Str, params: Vec, }, - MonoProj { + Proj { lhs: Box, rhs: Str, }, // e.g. T.U + ProjMethod { + lhs: Box, + method_name: Str, + args: Vec, + }, // e.g. Ts.__getitem__(N) FreeVar(FreeTyVar), // a reference to the type of other expression, see docs/compiler/inference.md Failure, // when failed to infer (e.g. get the type of `match`) /// used to represent `TyParam` is not initialized (see `erg_compiler::context::instantiate_tp`) @@ -1279,12 +1284,24 @@ impl PartialEq for Type { }, ) => ln == rn && lps == rps, ( - Self::MonoProj { lhs, rhs }, - Self::MonoProj { + Self::Proj { lhs, rhs }, + Self::Proj { lhs: rlhs, rhs: rrhs, }, ) => lhs == rlhs && rhs == rrhs, + ( + Self::ProjMethod { + lhs, + method_name, + args, + }, + Self::ProjMethod { + lhs: r, + method_name: rm, + args: ra, + }, + ) => lhs == r && method_name == rm && args == ra, (Self::FreeVar(fv), other) if fv.is_linked() => &*fv.crack() == other, (_self, Self::FreeVar(fv)) if fv.is_linked() => _self == &*fv.crack(), (Self::FreeVar(l), Self::FreeVar(r)) => l == r, @@ -1406,10 +1423,25 @@ impl LimitedDisplay for Type { write!(f, "{name}") } Self::FreeVar(fv) => fv.limited_fmt(f, limit), - Self::MonoProj { lhs, rhs } => { + Self::Proj { lhs, rhs } => { lhs.limited_fmt(f, limit - 1)?; write!(f, ".{rhs}") } + Self::ProjMethod { + lhs, + method_name, + args, + } => { + lhs.limited_fmt(f, limit - 1)?; + write!(f, ".{method_name}(")?; + for (i, arg) in args.iter().enumerate() { + if i != 0 { + write!(f, ", ")?; + } + arg.limited_fmt(f, limit - 1)?; + } + write!(f, ")") + } _ => write!(f, "{}", self.name()), } } @@ -1553,7 +1585,7 @@ impl HasLevel for Type { p.update_level(level); } } - Self::MonoProj { lhs, .. } => { + Self::Proj { lhs, .. } => { lhs.update_level(level); } Self::Refinement(refine) => { @@ -1616,7 +1648,7 @@ impl HasLevel for Type { p.lift(); } } - Self::MonoProj { lhs, .. } => { + Self::Proj { lhs, .. } => { lhs.lift(); } Self::Refinement(refine) => { @@ -1728,7 +1760,7 @@ impl Type { | Self::Poly { name, .. } | Self::BuiltinPoly { name, .. } | Self::PolyQVar { name, .. } - | Self::MonoProj { rhs: name, .. } => name.ends_with('!'), + | Self::Proj { rhs: name, .. } => name.ends_with('!'), Self::Refinement(refine) => refine.t.is_mut_type(), _ => false, } @@ -1899,8 +1931,9 @@ impl Type { FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => t.name(), FreeKind::NamedUnbound { name, .. } => name.clone(), FreeKind::Unbound { id, .. } => Str::from(format!("%{id}")), - }, // TODO: 中身がSomeなら表示したい - Self::MonoProj { .. } => Str::ever("MonoProj"), + }, + Self::Proj { .. } => Str::ever("MonoProj"), + Self::ProjMethod { .. } => Str::ever("MonoProjMethod"), Self::Failure => Str::ever("Failure"), Self::Uninited => Str::ever("Uninited"), } @@ -1979,7 +2012,7 @@ impl Type { Self::Poly { params, .. } | Self::BuiltinPoly { params, .. } => { params.iter().any(|tp| tp.has_qvar()) } - Self::MonoProj { lhs, .. } => lhs.has_qvar(), + Self::Proj { lhs, .. } => lhs.has_qvar(), _ => false, } } @@ -2023,7 +2056,7 @@ impl Type { Self::Poly { params, .. } | Self::BuiltinPoly { params, .. } | Self::PolyQVar { params, .. } => params.iter().all(|p| p.is_cachable()), - Self::MonoProj { lhs, .. } => lhs.is_cachable(), + Self::Proj { lhs, .. } => lhs.is_cachable(), _ => true, } } @@ -2074,7 +2107,7 @@ impl Type { Self::Poly { params, .. } | Self::BuiltinPoly { params, .. } | Self::PolyQVar { params, .. } => params.iter().any(|p| p.has_unbound_var()), - Self::MonoProj { lhs, .. } => lhs.has_no_unbound_var(), + Self::Proj { lhs, .. } => lhs.has_no_unbound_var(), _ => false, } } diff --git a/compiler/erg_type/typaram.rs b/compiler/erg_type/typaram.rs index 6859a124..971127b9 100644 --- a/compiler/erg_type/typaram.rs +++ b/compiler/erg_type/typaram.rs @@ -1,7 +1,9 @@ use std::cmp::Ordering; use std::fmt; use std::ops::{Add, Div, Mul, Neg, Range, RangeInclusive, Sub}; +use std::rc::Rc; +use erg_common::dict; use erg_common::dict::Dict; use erg_common::traits::LimitedDisplay; @@ -69,6 +71,15 @@ impl fmt::Display for OpKind { } } +impl OpKind { + pub fn is_comparison(&self) -> bool { + matches!( + self, + Self::Gt | Self::Lt | Self::Ge | Self::Le | Self::Eq | Self::Ne + ) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum IntervalOp { /// .. @@ -130,7 +141,7 @@ pub enum TyParam { Tuple(Vec), Dict(Dict), Mono(Str), - MonoProj { + Proj { obj: Box, attr: Str, }, @@ -166,8 +177,8 @@ impl PartialEq for TyParam { (Self::Tuple(l), Self::Tuple(r)) => l == r, (Self::Mono(l), Self::Mono(r)) | (Self::MonoQVar(l), Self::MonoQVar(r)) => l == r, ( - Self::MonoProj { obj, attr }, - Self::MonoProj { + Self::Proj { obj, attr }, + Self::Proj { obj: r_obj, attr: r_attr, }, @@ -278,7 +289,7 @@ impl LimitedDisplay for TyParam { } Self::Mono(name) => write!(f, "{}", name), Self::MonoQVar(name) => write!(f, "'{}", name), - Self::MonoProj { obj, attr } => { + Self::Proj { obj, attr } => { write!(f, "{}.", obj)?; write!(f, "{}", attr) } @@ -395,6 +406,39 @@ impl> From for TyParam { } } +impl TryFrom for ValueObj { + type Error = (); + fn try_from(tp: TyParam) -> Result { + match tp { + TyParam::Array(tps) => { + let mut vals = vec![]; + for tp in tps { + vals.push(ValueObj::try_from(tp)?); + } + Ok(ValueObj::Array(Rc::from(vals))) + } + TyParam::Tuple(tps) => { + let mut vals = vec![]; + for tp in tps { + vals.push(ValueObj::try_from(tp)?); + } + Ok(ValueObj::Tuple(Rc::from(vals))) + } + TyParam::Dict(tps) => { + let mut vals = dict! {}; + for (k, v) in tps { + vals.insert(ValueObj::try_from(k)?, ValueObj::try_from(v)?); + } + Ok(ValueObj::Dict(vals)) + } + TyParam::FreeVar(fv) if fv.is_linked() => ValueObj::try_from(fv.crack().clone()), + TyParam::Type(t) => Ok(ValueObj::builtin_t(*t)), + TyParam::Value(v) => Ok(v), + _ => panic!("Expected value, got {:?}", tp), + } + } +} + impl HasLevel for TyParam { fn level(&self) -> Option { match self { @@ -454,8 +498,8 @@ impl TyParam { Self::MonoQVar(name.into()) } - pub fn mono_proj>(obj: TyParam, attr: S) -> Self { - Self::MonoProj { + pub fn proj>(obj: TyParam, attr: S) -> Self { + Self::Proj { obj: Box::new(obj), attr: attr.into(), } @@ -485,6 +529,14 @@ impl TyParam { } } + pub fn as_type(&self) -> Option { + match self { + Self::Type(t) => Some(t.as_ref().clone()), + // TODO: Array, Dict, Set + _ => None, + } + } + #[inline] pub fn mutate(self) -> Self { Self::unary(OpKind::Mutate, self) @@ -580,7 +632,7 @@ impl TyParam { } } Self::Type(t) => t.has_qvar(), - Self::MonoProj { obj, .. } => obj.has_qvar(), + Self::Proj { obj, .. } => obj.has_qvar(), Self::Array(ts) | Self::Tuple(ts) | Self::Set(ts) => ts.iter().any(|t| t.has_qvar()), Self::UnaryOp { val, .. } => val.has_qvar(), Self::BinOp { lhs, rhs, .. } => lhs.has_qvar() || rhs.has_qvar(), @@ -594,7 +646,7 @@ impl TyParam { match self { Self::FreeVar(_) => false, Self::Type(t) => t.is_cachable(), - Self::MonoProj { obj, .. } => obj.is_cachable(), + Self::Proj { obj, .. } => obj.is_cachable(), Self::Array(ts) => ts.iter().all(|t| t.is_cachable()), Self::Tuple(ts) => ts.iter().all(|t| t.is_cachable()), Self::Set(ts) => ts.iter().all(|t| t.is_cachable()), @@ -606,6 +658,10 @@ impl TyParam { } } + pub fn is_unbound_var(&self) -> bool { + matches!(self, Self::FreeVar(fv) if fv.is_unbound() || fv.crack().is_unbound_var()) + } + pub fn has_unbound_var(&self) -> bool { match self { Self::FreeVar(fv) => { @@ -616,7 +672,7 @@ impl TyParam { } } Self::Type(t) => t.has_unbound_var(), - Self::MonoProj { obj, .. } => obj.has_unbound_var(), + Self::Proj { obj, .. } => obj.has_unbound_var(), Self::Array(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.has_unbound_var()), Self::UnaryOp { val, .. } => val.has_unbound_var(), Self::BinOp { lhs, rhs, .. } => lhs.has_unbound_var() || rhs.has_unbound_var(), @@ -651,8 +707,14 @@ impl TyParam { } pub fn update_constraint(&self, new_constraint: Constraint) { - if let Self::Type(t) = self { - t.update_constraint(new_constraint); + match self { + Self::Type(t) => { + t.update_constraint(new_constraint); + } + Self::FreeVar(fv) => { + fv.update_constraint(new_constraint); + } + _ => {} } } } @@ -695,6 +757,24 @@ impl TryFrom for Ordering { } impl TyParamOrdering { + pub const fn canbe_eq(self) -> bool { + matches!(self, LessEqual | GreaterEqual | Equal | Any) + } + pub const fn canbe_lt(self) -> bool { + matches!(self, Less | LessEqual | NotEqual | Any) + } + pub const fn canbe_gt(self) -> bool { + matches!(self, Greater | GreaterEqual | NotEqual | Any) + } + pub const fn canbe_le(self) -> bool { + matches!(self, Less | LessEqual | Equal | Any) + } + pub const fn canbe_ge(self) -> bool { + matches!(self, Greater | GreaterEqual | Equal | Any) + } + pub const fn canbe_ne(self) -> bool { + matches!(self, NotEqual | Any) + } pub const fn is_lt(&self) -> bool { matches!(self, Less | LessEqual | Any) } diff --git a/compiler/erg_type/value.rs b/compiler/erg_type/value.rs index 10d8cc18..6c5c2cad 100644 --- a/compiler/erg_type/value.rs +++ b/compiler/erg_type/value.rs @@ -502,7 +502,7 @@ impl ValueObj { Self::Float(_) => Type::Float, Self::Str(_) => Type::Str, Self::Bool(_) => Type::Bool, - // TODO: + // TODO: Zero Self::Array(arr) => array( arr.iter().next().unwrap().class(), TyParam::value(arr.len()), @@ -733,6 +733,52 @@ impl ValueObj { } } + pub fn try_lt(self, other: Self) -> Option { + match (self, other) { + (Self::Int(l), Self::Int(r)) => Some(Self::from(l < r)), + (Self::Nat(l), Self::Nat(r)) => Some(Self::from(l < r)), + (Self::Float(l), Self::Float(r)) => Some(Self::from(l < r)), + (Self::Int(l), Self::Nat(r)) => Some(Self::from(l < r as i32)), + (Self::Nat(l), Self::Int(r)) => Some(Self::from((l as i32) < r)), + (Self::Float(l), Self::Nat(r)) => Some(Self::from(l < r as f64)), + (Self::Nat(l), Self::Float(r)) => Some(Self::from((l as f64) < r)), + (Self::Float(l), Self::Int(r)) => Some(Self::from(l < r as f64)), + (Self::Int(l), Self::Float(r)) => Some(Self::from((l as f64) < r)), + (Self::Mut(m), other) => { + { + let ref_m = &mut *m.borrow_mut(); + *ref_m = mem::take(ref_m).try_lt(other)?; + } + Some(Self::Mut(m)) + } + (self_, Self::Mut(m)) => self_.try_lt(m.borrow().clone()), + _ => None, + } + } + + pub fn try_le(self, other: Self) -> Option { + match (self, other) { + (Self::Int(l), Self::Int(r)) => Some(Self::from(l <= r)), + (Self::Nat(l), Self::Nat(r)) => Some(Self::from(l <= r)), + (Self::Float(l), Self::Float(r)) => Some(Self::from(l <= r)), + (Self::Int(l), Self::Nat(r)) => Some(Self::from(l <= r as i32)), + (Self::Nat(l), Self::Int(r)) => Some(Self::from((l as i32) <= r)), + (Self::Float(l), Self::Nat(r)) => Some(Self::from(l <= r as f64)), + (Self::Nat(l), Self::Float(r)) => Some(Self::from((l as f64) <= r)), + (Self::Float(l), Self::Int(r)) => Some(Self::from(l <= r as f64)), + (Self::Int(l), Self::Float(r)) => Some(Self::from((l as f64) <= r)), + (Self::Mut(m), other) => { + { + let ref_m = &mut *m.borrow_mut(); + *ref_m = mem::take(ref_m).try_le(other)?; + } + Some(Self::Mut(m)) + } + (self_, Self::Mut(m)) => self_.try_le(m.borrow().clone()), + _ => None, + } + } + pub fn try_eq(self, other: Self) -> Option { match (self, other) { (Self::Int(l), Self::Int(r)) => Some(Self::from(l == r)), diff --git a/examples/dict.er b/examples/dict.er index 2001bdc5..d089e11d 100644 --- a/examples/dict.er +++ b/examples/dict.er @@ -1,7 +1,3 @@ -immut_dict: {Str: Int} = {"Alice": 1, "Bob": 2, "Charlie": 3} -# can insert / remove an element -telescoping_dict = {"Alice": 1, "Bob": 2, "Charlie": 3}.into {Str: Int; !*} -telescoping_dict.insert!("Dave", 4) -_ = telescoping_dict.remove!("Alice") -mut_content_dict: {Str: !Int} = {"Alice": !1, "Bob": !2, "Charlie": !3} -mut_content_dict["Bob"].update! 0 +immut_dict = {"Alice": 1, "Bob": 2, "Charlie": 3} +assert immut_dict["Alice"] == 1 +assert immut_dict["Bob"] == 2 diff --git a/tests/test.rs b/tests/test.rs index 90ca0349..1c9599ac 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -21,6 +21,11 @@ fn exec_class() -> Result<(), ()> { expect_success("examples/class.er") } +/*#[test] +fn exec_dict() -> Result<(), ()> { + expect_success("examples/dict.er") +}*/ + #[test] fn exec_fib() -> Result<(), ()> { expect_success("examples/fib.er")