diff --git a/compiler/erg_compiler/context/initialize/mod.rs b/compiler/erg_compiler/context/initialize/mod.rs index 98e424c1..5645bd2c 100644 --- a/compiler/erg_compiler/context/initialize/mod.rs +++ b/compiler/erg_compiler/context/initialize/mod.rs @@ -101,7 +101,7 @@ impl Context { let mut tv_ctx = TyVarContext::new(self.level, ctx.type_params_bounds(), self); let t = Self::instantiate_t(t, &mut tv_ctx); if let Some((_, root_ctx)) = self.poly_types.get_mut(&t.name()) { - root_ctx.specializations.push((t, ctx)); + root_ctx.method_defs.push((t, ctx)); } else { let name = VarName::from_str(t.name()); self.locals diff --git a/compiler/erg_compiler/context/mod.rs b/compiler/erg_compiler/context/mod.rs index ef9eef24..6c90f753 100644 --- a/compiler/erg_compiler/context/mod.rs +++ b/compiler/erg_compiler/context/mod.rs @@ -192,6 +192,7 @@ pub enum ContextKind { Func, Proc, Class, + MethodDefs, Trait, StructuralTrait, Patch(Type), @@ -230,8 +231,8 @@ pub struct Context { // patchによってsuper class/traitになったものはここに含まれない pub(crate) super_classes: Vec, // if self is a patch, means patch classes pub(crate) super_traits: Vec, // if self is not a trait, means implemented traits - // specialized contexts, If self is a type - pub(crate) specializations: Vec<(Type, Context)>, + // method definitions, if the context is a type + pub(crate) method_defs: Vec<(Type, Context)>, /// K: method name, V: impl patch /// Provided methods can switch implementations on a scope-by-scope basis /// K: メソッド名, V: それを実装するパッチたち @@ -357,7 +358,7 @@ impl Context { outer: outer.map(Box::new), super_classes, super_traits, - specializations: vec![], + method_defs: vec![], const_param_defaults: Dict::default(), method_impl_patches: Dict::default(), trait_impls: Dict::default(), @@ -539,7 +540,7 @@ impl Context { Ok(()) } - pub(crate) fn pop(&mut self) -> Result<(), TyCheckErrors> { + pub(crate) fn pop(&mut self) -> Result { let mut uninited_errs = TyCheckErrors::empty(); for (name, vi) in self.decls.iter() { uninited_errs.push(TyCheckError::uninitialized_error( @@ -551,12 +552,14 @@ impl Context { )); } if let Some(parent) = &mut self.outer { - *self = mem::take(parent); + let parent = mem::take(parent); + let ctx = mem::take(self); + *self = *parent; log!(info "{}: current namespace: {}", fn_name!(), self.name); if !uninited_errs.is_empty() { Err(uninited_errs) } else { - Ok(()) + Ok(ctx) } } else { Err(TyCheckErrors::from(TyCheckError::checker_bug( diff --git a/compiler/erg_compiler/context/register.rs b/compiler/erg_compiler/context/register.rs index 7b111b4d..03e969c7 100644 --- a/compiler/erg_compiler/context/register.rs +++ b/compiler/erg_compiler/context/register.rs @@ -328,56 +328,53 @@ impl Context { pub(crate) fn preregister(&mut self, block: &ast::Block) -> TyCheckResult<()> { for expr in block.iter() { if let ast::Expr::Def(def) = expr { - let id = Some(def.body.id); - let __name__ = def.sig.ident().map(|i| i.inspect()); - match &def.sig { - ast::Signature::Subr(sig) => { - if sig.is_const() { - let (obj, const_t) = - match self.eval_const_block(&def.body.block, __name__) { - Ok(obj) => (obj.clone(), enum_t(set! {obj})), - Err(e) => { - return Err(e); - } - }; - if let Some(spec) = sig.return_t_spec.as_ref() { - let spec_t = self.instantiate_typespec(spec, PreRegister)?; - self.sub_unify( - &const_t, - &spec_t, - Some(def.body.loc()), - None, - None, - )?; - } - self.register_const(__name__.unwrap(), obj); - } else { - let opt_ret_t = if let Some(spec) = sig.return_t_spec.as_ref() { - let spec_t = self.instantiate_typespec(spec, PreRegister)?; - Some(spec_t) - } else { - None - }; - self.declare_sub(sig, opt_ret_t, id)?; + self.preregister_def(def)?; + } + } + Ok(()) + } + + pub(crate) fn preregister_def(&mut self, def: &ast::Def) -> TyCheckResult<()> { + let id = Some(def.body.id); + let __name__ = def.sig.ident().map(|i| i.inspect()); + match &def.sig { + ast::Signature::Subr(sig) => { + if sig.is_const() { + let (obj, const_t) = match self.eval_const_block(&def.body.block, __name__) { + Ok(obj) => (obj.clone(), enum_t(set! {obj})), + Err(e) => { + return Err(e); } + }; + if let Some(spec) = sig.return_t_spec.as_ref() { + let spec_t = self.instantiate_typespec(spec, PreRegister)?; + self.sub_unify(&const_t, &spec_t, Some(def.body.loc()), None, None)?; } - ast::Signature::Var(sig) if sig.is_const() => { - let (obj, const_t) = match self.eval_const_block(&def.body.block, __name__) - { - Ok(obj) => (obj.clone(), enum_t(set! {obj})), - Err(e) => { - return Err(e); - } - }; - if let Some(spec) = sig.t_spec.as_ref() { - let spec_t = self.instantiate_typespec(spec, PreRegister)?; - self.sub_unify(&const_t, &spec_t, Some(def.body.loc()), None, None)?; - } - self.register_const(__name__.unwrap(), obj); - } - _ => {} + self.register_const(__name__.unwrap(), obj); + } else { + let opt_ret_t = if let Some(spec) = sig.return_t_spec.as_ref() { + let spec_t = self.instantiate_typespec(spec, PreRegister)?; + Some(spec_t) + } else { + None + }; + self.declare_sub(sig, opt_ret_t, id)?; } } + ast::Signature::Var(sig) if sig.is_const() => { + let (obj, const_t) = match self.eval_const_block(&def.body.block, __name__) { + Ok(obj) => (obj.clone(), enum_t(set! {obj})), + Err(e) => { + return Err(e); + } + }; + if let Some(spec) = sig.t_spec.as_ref() { + let spec_t = self.instantiate_typespec(spec, PreRegister)?; + self.sub_unify(&const_t, &spec_t, Some(def.body.loc()), None, None)?; + } + self.register_const(__name__.unwrap(), obj); + } + _ => {} } Ok(()) } diff --git a/compiler/erg_compiler/lower.rs b/compiler/erg_compiler/lower.rs index 1ed7af22..50f0b91f 100644 --- a/compiler/erg_compiler/lower.rs +++ b/compiler/erg_compiler/lower.rs @@ -9,6 +9,7 @@ use erg_common::{enum_unwrap, fmt_option, fn_name, get_hash, log, switch_lang, S use erg_parser::ast; use erg_parser::ast::AST; +use erg_parser::token::{Token, TokenKind}; use erg_type::constructors::{array, array_mut, class, free_var, func, poly_class, proc, quant}; use erg_type::free::Constraint; use erg_type::typaram::TyParam; @@ -338,14 +339,36 @@ impl ASTLowerer { hir_args.push_kw(hir::KwArg::new(arg.keyword, self.lower_expr(arg.expr)?)); } let obj = self.lower_expr(*call.obj)?; - let t = self.ctx.get_call_t( + let sig_t = self.ctx.get_call_t( &obj, &call.method_name, &hir_args.pos_args, &hir_args.kw_args, &self.ctx.name, )?; - Ok(hir::Call::new(obj, call.method_name, hir_args, t)) + Ok(hir::Call::new(obj, call.method_name, hir_args, sig_t)) + } + + fn lower_pack(&mut self, pack: ast::DataPack) -> LowerResult { + log!(info "entered {}({pack})", fn_name!()); + let class = self.lower_expr(*pack.class)?; + let args = self.lower_record(pack.args)?; + let args = vec![hir::PosArg::new(hir::Expr::Record(args))]; + let method_name = Token::new( + TokenKind::Symbol, + Str::rc("new"), + pack.connector.lineno, + pack.connector.col_begin, + ); + let sig_t = self.ctx.get_call_t( + &class, + &Some(method_name.clone()), + &args, + &[], + &self.ctx.name, + )?; + let args = hir::Args::new(args, vec![], None); + Ok(hir::Call::new(class, Some(method_name), args, sig_t)) } /// TODO: varargs @@ -523,6 +546,40 @@ impl ASTLowerer { Ok(hir::Def::new(hir::Signature::Subr(sig), body)) } + fn lower_method_defs(&mut self, method_defs: ast::MethodDefs) -> LowerResult { + log!(info "entered {}({method_defs})", fn_name!()); + let mut hir_defs = hir::RecordAttrs::new(); + let class = self + .ctx + .instantiate_typespec(&method_defs.class, RegistrationMode::Normal)?; + self.ctx + .grow(&class.name(), ContextKind::MethodDefs, Private)?; + for def in method_defs.defs.iter() { + self.ctx.preregister_def(def)?; + } + for def in method_defs.defs.into_iter() { + let def = self.lower_def(def)?; + hir_defs.push(def); + } + match self.ctx.pop() { + Ok(ctx) => { + if let Some((_, class_root)) = self.ctx.poly_types.get_mut(&class.name()) { + class_root.method_defs.push((class, ctx)); + } else { + todo!() + } + } + Err(mut errs) => { + self.errs.append(&mut errs); + } + } + Ok(hir::MethodDefs::new( + method_defs.class, + method_defs.vis, + hir_defs, + )) + } + // Call.obj == Accessor cannot be type inferred by itself (it can only be inferred with arguments) // so turn off type checking (check=false) fn lower_expr(&mut self, expr: ast::Expr) -> LowerResult { @@ -536,8 +593,10 @@ impl ASTLowerer { ast::Expr::BinOp(bin) => Ok(hir::Expr::BinOp(self.lower_bin(bin)?)), ast::Expr::UnaryOp(unary) => Ok(hir::Expr::UnaryOp(self.lower_unary(unary)?)), ast::Expr::Call(call) => Ok(hir::Expr::Call(self.lower_call(call)?)), + ast::Expr::DataPack(pack) => Ok(hir::Expr::Call(self.lower_pack(pack)?)), ast::Expr::Lambda(lambda) => Ok(hir::Expr::Lambda(self.lower_lambda(lambda)?)), ast::Expr::Def(def) => Ok(hir::Expr::Def(self.lower_def(def)?)), + ast::Expr::MethodDefs(defs) => Ok(hir::Expr::MethodDefs(self.lower_method_defs(defs)?)), other => todo!("{other}"), } } diff --git a/compiler/erg_parser/ast.rs b/compiler/erg_parser/ast.rs index 11ef72e8..a1e824b0 100644 --- a/compiler/erg_parser/ast.rs +++ b/compiler/erg_parser/ast.rs @@ -897,6 +897,7 @@ impl Call { #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct DataPack { pub class: Box, + pub connector: Token, pub args: Record, } @@ -915,9 +916,10 @@ impl Locational for DataPack { } impl DataPack { - pub fn new(class: Expr, args: Record) -> Self { + pub fn new(class: Expr, connector: Token, args: Record) -> Self { Self { class: Box::new(class), + connector, args, } } diff --git a/compiler/erg_parser/desugar.rs b/compiler/erg_parser/desugar.rs index 9e288685..a4ab3198 100644 --- a/compiler/erg_parser/desugar.rs +++ b/compiler/erg_parser/desugar.rs @@ -330,7 +330,7 @@ impl Desugarer { let class = self.rec_desugar_shortened_record(*pack.class); let rec = self.desugar_shortened_record_inner(rec); let args = Record::Normal(rec); - Expr::DataPack(DataPack::new(class, args)) + Expr::DataPack(DataPack::new(class, pack.connector, args)) } else { Expr::DataPack(pack) } diff --git a/compiler/erg_parser/parse.rs b/compiler/erg_parser/parse.rs index 5a55c460..1c7c1879 100644 --- a/compiler/erg_parser/parse.rs +++ b/compiler/erg_parser/parse.rs @@ -997,7 +997,7 @@ impl Parser { .map_err(|_| self.stack_dec())?; match container { BraceContainer::Record(args) => { - let pack = DataPack::new(maybe_class, args); + let pack = DataPack::new(maybe_class, vis, args); stack.push(ExprOrOp::Expr(Expr::DataPack(pack))); } BraceContainer::Dict(dict) => todo!("{dict}"),