From db84321ff8c90884e4406e14521b4c9b3bc0dc72 Mon Sep 17 00:00:00 2001 From: Shunsuke Shibayama Date: Thu, 29 Sep 2022 21:50:28 +0900 Subject: [PATCH 1/6] Add type definitions for `open!` and `with!` --- compiler/erg_compiler/context/eval.rs | 18 ++++++++- .../erg_compiler/context/initialize/mod.rs | 38 +++++++++++++++++++ compiler/erg_compiler/context/instantiate.rs | 15 ++++++++ compiler/erg_compiler/context/tyvar.rs | 4 +- 4 files changed, 73 insertions(+), 2 deletions(-) diff --git a/compiler/erg_compiler/context/eval.rs b/compiler/erg_compiler/context/eval.rs index 9bcb9b04a..710b136b3 100644 --- a/compiler/erg_compiler/context/eval.rs +++ b/compiler/erg_compiler/context/eval.rs @@ -14,7 +14,8 @@ use erg_parser::ast::*; use erg_parser::token::{Token, TokenKind}; use erg_type::constructors::{ - builtin_mono, builtin_poly, mono_proj, poly, ref_, ref_mut, refinement, subr_t, v_enum, + and, builtin_mono, builtin_poly, mono_proj, not, or, poly, ref_, ref_mut, refinement, subr_t, + v_enum, }; use erg_type::typaram::{OpKind, TyParam}; use erg_type::value::ValueObj; @@ -807,6 +808,21 @@ impl Context { } Ok(poly(path, name, params)) } + Type::And(l, r) => { + let l = self.eval_t_params(*l, level, t_loc)?; + let r = self.eval_t_params(*r, level, t_loc)?; + Ok(and(l, r)) + } + Type::Or(l, r) => { + let l = self.eval_t_params(*l, level, t_loc)?; + let r = self.eval_t_params(*r, level, t_loc)?; + Ok(or(l, r)) + } + Type::Not(l, r) => { + let l = self.eval_t_params(*l, level, t_loc)?; + let r = self.eval_t_params(*r, level, t_loc)?; + Ok(not(l, r)) + } other if other.is_monomorphic() => Ok(other), other => todo!("{other}"), } diff --git a/compiler/erg_compiler/context/initialize/mod.rs b/compiler/erg_compiler/context/initialize/mod.rs index 8aed6b91f..dfa9a7cdf 100644 --- a/compiler/erg_compiler/context/initialize/mod.rs +++ b/compiler/erg_compiler/context/initialize/mod.rs @@ -204,6 +204,7 @@ impl Context { // REVIEW: Mutatable? let mut mutizable = Self::builtin_mono_trait("Mutizable", 2); mutizable.register_builtin_decl("MutType!", Type, Public); + let pathlike = Self::builtin_mono_trait("PathLike", 2); let mut in_ = Self::builtin_poly_trait("In", vec![PS::t("T", NonDefault)], 2); let params = vec![PS::t("T", NonDefault)]; let input = Self::builtin_poly_trait("Input", params.clone(), 2); @@ -326,6 +327,7 @@ impl Context { self.register_builtin_type(builtin_mono("Mutable"), mutable, Const); self.register_builtin_type(builtin_mono("Immutizable"), immutizable, Const); self.register_builtin_type(builtin_mono("Mutizable"), mutizable, Const); + self.register_builtin_type(builtin_mono("PathLike"), pathlike, Const); self.register_builtin_type( builtin_poly("Input", vec![ty_tp(mono_q("T"))]), input, @@ -619,6 +621,7 @@ impl Context { let mut str_ = Self::builtin_mono_class("Str", 10); str_.register_superclass(Obj, &obj); str_.register_marker_trait(builtin_mono("Ord")); + str_.register_marker_trait(builtin_mono("PathLike")); str_.register_builtin_impl( "replace", fn_met( @@ -1327,6 +1330,7 @@ impl Context { builtin_mono("Mutable"), str_mut_mutable, ); + let file_mut = Self::builtin_mono_class("File!", 2); let array_t = builtin_poly("Array", vec![ty_tp(mono_q("T")), mono_q_tp("N")]); let array_mut_t = builtin_poly("Array!", vec![ty_tp(mono_q("T")), mono_q_tp("N")]); let mut array_mut_ = Self::builtin_poly_class( @@ -1503,6 +1507,7 @@ impl Context { self.register_builtin_type(builtin_mono("Ratio!"), ratio_mut, Const); self.register_builtin_type(builtin_mono("Bool!"), bool_mut, Const); self.register_builtin_type(builtin_mono("Str!"), str_mut, Const); + self.register_builtin_type(builtin_mono("File!"), file_mut, Const); self.register_builtin_type(array_mut_t, array_mut_, Const); self.register_builtin_type(range_t, range, Const); self.register_builtin_type(builtin_mono("Tuple"), tuple_, Const); @@ -1684,6 +1689,37 @@ impl Context { None, NoneType, ); + let t_open = proc( + vec![param_t("file", mono_q("P"))], + None, + vec![ + param_t("mode", Str), + param_t("buffering", Int), + param_t("encoding", or(Str, NoneType)), + param_t("errors", or(Str, NoneType)), + param_t("newline", or(Str, NoneType)), + param_t("closefd", Bool), + // param_t("opener", option), + ], + builtin_mono("File!"), + ); + let t_open = quant( + t_open, + set! {subtypeof(mono_q("P"), builtin_mono("PathLike"))}, + ); + // TODO: T <: With + let t_with = nd_proc( + vec![ + param_t("obj", mono_q("T")), + param_t("p!", nd_proc(vec![anon(mono_q("T"))], None, mono_q("U"))), + ], + None, + mono_q("U"), + ); + let t_with = quant( + t_with, + set! {static_instance("T", Type), static_instance("U", Type)}, + ); self.register_builtin_impl("dir!", t_dir, Immutable, Private); self.register_builtin_impl("print!", t_print, Immutable, Private); self.register_builtin_impl("id!", t_id, Immutable, Private); @@ -1691,6 +1727,8 @@ impl Context { self.register_builtin_impl("if!", t_if, Immutable, Private); self.register_builtin_impl("for!", t_for, Immutable, Private); self.register_builtin_impl("while!", t_while, Immutable, Private); + self.register_builtin_impl("open!", t_open, Immutable, Private); + self.register_builtin_impl("with!", t_with, Immutable, Private); } fn init_builtin_operators(&mut self) { diff --git a/compiler/erg_compiler/context/instantiate.rs b/compiler/erg_compiler/context/instantiate.rs index f48443b26..eaa6af6fd 100644 --- a/compiler/erg_compiler/context/instantiate.rs +++ b/compiler/erg_compiler/context/instantiate.rs @@ -893,6 +893,21 @@ impl Context { fv.update_constraint(new_constraint); Ok(FreeVar(fv)) } + And(l, r) => { + let l = self.instantiate_t(*l, tv_ctx, loc)?; + let r = self.instantiate_t(*r, tv_ctx, loc)?; + Ok(and(l, r)) + } + Or(l, r) => { + let l = self.instantiate_t(*l, tv_ctx, loc)?; + let r = self.instantiate_t(*r, tv_ctx, loc)?; + Ok(or(l, r)) + } + Not(l, r) => { + let l = self.instantiate_t(*l, tv_ctx, loc)?; + let r = self.instantiate_t(*r, tv_ctx, loc)?; + Ok(not(l, r)) + } other if other.is_monomorphic() => Ok(other), other => todo!("{other}"), } diff --git a/compiler/erg_compiler/context/tyvar.rs b/compiler/erg_compiler/context/tyvar.rs index 201fc3f96..34c394648 100644 --- a/compiler/erg_compiler/context/tyvar.rs +++ b/compiler/erg_compiler/context/tyvar.rs @@ -373,7 +373,9 @@ impl Context { } Type::BuiltinPoly { name, mut params } => { let typ = builtin_poly(&name, params.clone()); - let (_, ctx) = self.get_nominal_type_ctx(&typ).unwrap(); + let (_, ctx) = self + .get_nominal_type_ctx(&typ) + .unwrap_or_else(|| todo!("{typ} not found")); let variances = ctx.type_params_variance(); for (param, variance) in params.iter_mut().zip(variances.into_iter()) { *param = self.deref_tp(mem::take(param), variance, loc)?; From bb73e6e4da9fe09f8b86d6df83b320a51e7c44ce Mon Sep 17 00:00:00 2001 From: Shunsuke Shibayama Date: Thu, 29 Sep 2022 22:07:54 +0900 Subject: [PATCH 2/6] Update opcode.rs --- compiler/erg_common/opcode.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/erg_common/opcode.rs b/compiler/erg_common/opcode.rs index 61d668822..c0f0c20b0 100644 --- a/compiler/erg_common/opcode.rs +++ b/compiler/erg_common/opcode.rs @@ -65,6 +65,8 @@ pub enum Opcode { LOAD_ASSERTION_ERROR = 74, LIST_TO_TUPLE = 82, RETURN_VALUE = 83, + POP_BLOCK = 87, + POP_EXCEPT = 89, /* ↓ These opcodes take an arg */ STORE_NAME = 90, DELETE_NAME = 91, @@ -92,6 +94,7 @@ pub enum Opcode { LOAD_GLOBAL = 116, IS_OP = 117, CONTAINS_OP = 118, + RERAISE = 119, LOAD_FAST = 124, STORE_FAST = 125, DELETE_FAST = 126, @@ -103,6 +106,7 @@ pub enum Opcode { STORE_DEREF = 137, CALL_FUNCTION_KW = 141, CALL_FUNCTION_EX = 142, + SETUP_WITH = 143, LOAD_METHOD = 160, CALL_METHOD = 161, LIST_EXTEND = 162, @@ -210,6 +214,8 @@ impl From for Opcode { 74 => LOAD_ASSERTION_ERROR, 82 => LIST_TO_TUPLE, 83 => RETURN_VALUE, + 87 => POP_BLOCK, + 89 => POP_EXCEPT, /* ↓ These opcodes take an arg */ 90 => STORE_NAME, 91 => DELETE_NAME, @@ -237,6 +243,7 @@ impl From for Opcode { 116 => LOAD_GLOBAL, 117 => IS_OP, 118 => CONTAINS_OP, + 119 => RERAISE, 124 => LOAD_FAST, 125 => STORE_FAST, 126 => DELETE_FAST, @@ -248,6 +255,7 @@ impl From for Opcode { 137 => STORE_DEREF, 141 => CALL_FUNCTION_KW, 142 => CALL_FUNCTION_EX, + 143 => SETUP_WITH, 160 => LOAD_METHOD, 161 => CALL_METHOD, 162 => LIST_EXTEND, From cd168ef13168fae69623197953825b3da6375e0f Mon Sep 17 00:00:00 2001 From: Shunsuke Shibayama Date: Thu, 29 Sep 2022 23:56:02 +0900 Subject: [PATCH 3/6] Impl `with!` --- compiler/erg_compiler/codegen.rs | 67 +++++++++++++++++-- .../erg_compiler/context/initialize/mod.rs | 33 ++++++++- compiler/erg_type/codeobj.rs | 3 + 3 files changed, 98 insertions(+), 5 deletions(-) diff --git a/compiler/erg_compiler/codegen.rs b/compiler/erg_compiler/codegen.rs index 44788626c..1fa98ac81 100644 --- a/compiler/erg_compiler/codegen.rs +++ b/compiler/erg_compiler/codegen.rs @@ -218,6 +218,7 @@ fn convert_to_python_attr(class: &str, uniq_obj_name: Option<&str>, name: Str) - ("Array!", _, "push!") => Str::ever("append"), ("Complex" | "Float" | "Ratio" | "Int" | "Nat" | "Bool", _, "Real") => Str::ever("real"), ("Complex" | "Float" | "Ratio" | "Int" | "Nat" | "Bool", _, "Imag") => Str::ever("imag"), + ("File!", _, "read") => Str::ever("read"), (_, _, "__new__") => Str::ever("__call__"), ("StringIO!", _, "getvalue!") => Str::ever("getvalue"), ("Module", Some("importlib"), "reload!") => Str::ever("reload"), @@ -257,6 +258,7 @@ fn convert_to_python_name(name: Str) -> Str { "import" => Str::ever("__import__"), "input!" => Str::ever("input"), "log" => Str::ever("print"), // TODO: log != print (prints after executing) + "open!" => Str::ever("open"), "print!" => Str::ever("print"), "py" | "pyimport" => Str::ever("__import__"), "quit" | "exit" => Str::ever("quit"), @@ -1354,6 +1356,58 @@ impl CodeGenerator { pop_jump_points } + fn emit_with_instr(&mut self, args: Args) { + log!(info "entered {}", fn_name!()); + let mut args = args; + let expr = args.remove(0); + let lambda = enum_unwrap!(args.remove(0), Expr::Lambda); + let params = self.gen_param_names(&lambda.params); + self.emit_expr(expr); + let idx_setup_with = self.cur_block().lasti; + self.write_instr(SETUP_WITH); + self.write_arg(0); + // push __exit__, __enter__() to the stack + self.stack_inc_n(2); + let lambda_line = lambda.body.last().unwrap().ln_begin().unwrap_or(0); + self.emit_frameless_block(lambda.body, params); + let stash = Identifier::private_with_line(Str::from(fresh_varname()), lambda_line); + self.emit_store_instr(stash.clone(), Name); + self.write_instr(POP_BLOCK); + self.write_arg(0); + self.emit_load_const(ValueObj::None); + self.write_instr(DUP_TOP); + self.write_arg(0); + self.stack_inc(); + self.write_instr(DUP_TOP); + self.write_arg(0); + self.stack_inc(); + self.write_instr(CALL_FUNCTION); + self.write_arg(3); + self.stack_dec_n(3 - 1); + self.emit_pop_top(); + self.emit_load_const(ValueObj::None); + self.write_instr(RETURN_VALUE); + self.write_arg(0); + self.edit_code( + idx_setup_with + 1, + (self.cur_block().lasti - idx_setup_with - 2) / 2, + ); + self.write_instr(WITH_EXCEPT_START); + self.write_arg(0); + let idx_pop_jump_if_true = self.cur_block().lasti; + self.write_instr(POP_JUMP_IF_TRUE); + self.write_arg(0); + self.write_instr(RERAISE); + self.write_arg(1); + self.edit_code(idx_pop_jump_if_true + 1, self.cur_block().lasti / 2); + self.emit_pop_top(); + self.emit_pop_top(); + self.emit_pop_top(); + self.write_instr(POP_EXCEPT); + self.write_arg(0); + self.emit_load_name_instr(stash); + } + fn emit_call(&mut self, call: Call) { log!(info "entered {} ({call})", fn_name!()); if let Some(method_name) = call.method_name { @@ -1379,6 +1433,7 @@ impl CodeGenerator { "for" | "for!" => self.emit_for_instr(args), "if" | "if!" => self.emit_if_instr(args), "match" | "match!" => self.emit_match_instr(args, true), + "with!" => self.emit_with_instr(args), "import" => { if !self.module_type_loaded { self.load_module_type(); @@ -1418,14 +1473,14 @@ impl CodeGenerator { } if let Some(var_args) = &args.var_args { if pos_len > 0 { - self.write_instr(Opcode::BUILD_LIST); + self.write_instr(BUILD_LIST); self.write_arg(pos_len as u8); } self.emit_expr(var_args.expr.clone()); if pos_len > 0 { - self.write_instr(Opcode::LIST_EXTEND); + self.write_instr(LIST_EXTEND); self.write_arg(1); - self.write_instr(Opcode::LIST_TO_TUPLE); + self.write_instr(LIST_TO_TUPLE); self.write_arg(0); } } @@ -1652,8 +1707,12 @@ impl CodeGenerator { /// forブロックなどで使う fn emit_frameless_block(&mut self, block: Block, params: Vec) { log!(info "entered {}", fn_name!()); + let line = block.ln_begin().unwrap_or(0); for param in params { - self.emit_store_instr(Identifier::private(param), Name); + self.emit_store_instr( + Identifier::public_with_line(Token::dummy(), param, line), + Name, + ); } for expr in block.into_iter() { self.emit_expr(expr); diff --git a/compiler/erg_compiler/context/initialize/mod.rs b/compiler/erg_compiler/context/initialize/mod.rs index dfa9a7cdf..1f83576d1 100644 --- a/compiler/erg_compiler/context/initialize/mod.rs +++ b/compiler/erg_compiler/context/initialize/mod.rs @@ -205,6 +205,19 @@ impl Context { let mut mutizable = Self::builtin_mono_trait("Mutizable", 2); mutizable.register_builtin_decl("MutType!", Type, Public); let pathlike = Self::builtin_mono_trait("PathLike", 2); + let mut readable = Self::builtin_mono_trait("Readable", 2); + let t_read = fn_met( + ref_(mono_q("Self")), + vec![], + None, + vec![param_t("n", Int)], + Str, + ); + let t_read = quant( + t_read, + set! { subtypeof(mono_q("Self"), builtin_mono("Readable")) }, + ); + readable.register_builtin_impl("read", t_read, Immutable, Public); let mut in_ = Self::builtin_poly_trait("In", vec![PS::t("T", NonDefault)], 2); let params = vec![PS::t("T", NonDefault)]; let input = Self::builtin_poly_trait("Input", params.clone(), 2); @@ -1330,7 +1343,25 @@ impl Context { builtin_mono("Mutable"), str_mut_mutable, ); - let file_mut = Self::builtin_mono_class("File!", 2); + let mut file_mut = Self::builtin_mono_class("File!", 2); + let mut file_mut_readable = Self::builtin_methods("Readable", 1); + file_mut_readable.register_builtin_impl( + "read", + fn_met( + ref_(builtin_mono("File!")), + vec![], + None, + vec![param_t("n", Int)], + Str, + ), + Immutable, + Public, + ); + file_mut.register_trait( + builtin_mono("File!"), + builtin_mono("Readable"), + file_mut_readable, + ); let array_t = builtin_poly("Array", vec![ty_tp(mono_q("T")), mono_q_tp("N")]); let array_mut_t = builtin_poly("Array!", vec![ty_tp(mono_q("T")), mono_q_tp("N")]); let mut array_mut_ = Self::builtin_poly_class( diff --git a/compiler/erg_type/codeobj.rs b/compiler/erg_type/codeobj.rs index ccddd4982..3ab9d9c91 100644 --- a/compiler/erg_type/codeobj.rs +++ b/compiler/erg_type/codeobj.rs @@ -439,6 +439,9 @@ impl CodeObj { Opcode::JUMP_FORWARD => { write!(instrs, "{} (to {})", arg, idx + arg * 2 + 2).unwrap(); } + Opcode::SETUP_WITH => { + write!(instrs, "{} (to {})", arg, idx + arg * 2 + 2).unwrap(); + } Opcode::JUMP_ABSOLUTE => { write!(instrs, "{} (to {})", arg, arg * 2).unwrap(); } From 96c552713484d009fb57f384f507f80e933ae08a Mon Sep 17 00:00:00 2001 From: Shunsuke Shibayama Date: Fri, 30 Sep 2022 01:22:22 +0900 Subject: [PATCH 4/6] Improve: inferring the overall type from the method --- .../erg_compiler/context/initialize/mod.rs | 26 ++++++++++++++++--- compiler/erg_compiler/context/inquire.rs | 22 ++++++++++++++-- compiler/erg_compiler/context/mod.rs | 3 +++ compiler/erg_compiler/context/register.rs | 8 ++++++ examples/trait.er | 2 ++ examples/with.er | 2 ++ 6 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 examples/with.er diff --git a/compiler/erg_compiler/context/initialize/mod.rs b/compiler/erg_compiler/context/initialize/mod.rs index 1f83576d1..8376719c0 100644 --- a/compiler/erg_compiler/context/initialize/mod.rs +++ b/compiler/erg_compiler/context/initialize/mod.rs @@ -100,8 +100,7 @@ impl Context { } fn register_mono_type(&mut self, t: Type, ctx: Self, muty: Mutability) { - // FIXME: recursive search - if self.mono_types.contains_key(&t.name()) { + if self.rec_get_mono_type(&t.name()).is_some() { panic!("{} has already been registered", t.name()); } else if self.rec_get_const_obj(&t.name()).is_some() { panic!("{} has already been registered as const", t.name()); @@ -123,6 +122,16 @@ impl Context { ); } } + if ctx.kind == ContextKind::Trait { + for method in ctx.decls.keys() { + if let Some(traits) = self.method_traits.get_mut(method.inspect()) { + traits.push(t.clone()); + } else { + self.method_traits + .insert(method.inspect().clone(), vec![t.clone()]); + } + } + } self.mono_types.insert(name, (t, ctx)); } } @@ -154,6 +163,16 @@ impl Context { ); } } + if ctx.kind == ContextKind::Trait { + for method in ctx.decls.keys() { + if let Some(traits) = self.method_traits.get_mut(method.inspect()) { + traits.push(t.clone()); + } else { + self.method_traits + .insert(method.inspect().clone(), vec![t.clone()]); + } + } + } self.poly_types.insert(name, (t, ctx)); } } @@ -217,7 +236,7 @@ impl Context { t_read, set! { subtypeof(mono_q("Self"), builtin_mono("Readable")) }, ); - readable.register_builtin_impl("read", t_read, Immutable, Public); + readable.register_builtin_decl("read", t_read, Public); let mut in_ = Self::builtin_poly_trait("In", vec![PS::t("T", NonDefault)], 2); let params = vec![PS::t("T", NonDefault)]; let input = Self::builtin_poly_trait("Input", params.clone(), 2); @@ -341,6 +360,7 @@ impl Context { self.register_builtin_type(builtin_mono("Immutizable"), immutizable, Const); self.register_builtin_type(builtin_mono("Mutizable"), mutizable, Const); self.register_builtin_type(builtin_mono("PathLike"), pathlike, Const); + self.register_builtin_type(builtin_mono("Readable"), readable, Const); self.register_builtin_type( builtin_poly("Input", vec![ty_tp(mono_q("T"))]), input, diff --git a/compiler/erg_compiler/context/inquire.rs b/compiler/erg_compiler/context/inquire.rs index 8e99d5506..59c9dd0e5 100644 --- a/compiler/erg_compiler/context/inquire.rs +++ b/compiler/erg_compiler/context/inquire.rs @@ -495,6 +495,10 @@ impl Context { self.get_similar_attr_from_singular(obj, method_name.inspect()), )); } + if let Some(trait_) = self.rec_get_method_traits(method_name) { + let (_, ctx) = self.get_nominal_type_ctx(trait_).unwrap(); + return ctx.rec_get_var_t(method_name, input, namespace); + } // TODO: patch Err(TyCheckError::no_attr_error( self.cfg.input.clone(), @@ -1504,7 +1508,7 @@ impl Context { } } - fn rec_get_mono_type(&self, name: &str) -> Option<(&Type, &Context)> { + pub(crate) fn rec_get_mono_type(&self, name: &str) -> Option<(&Type, &Context)> { if let Some((t, ctx)) = self.mono_types.get(name) { Some((t, ctx)) } else if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) { @@ -1514,7 +1518,7 @@ impl Context { } } - fn rec_get_poly_type(&self, name: &str) -> Option<(&Type, &Context)> { + pub(crate) fn rec_get_poly_type(&self, name: &str) -> Option<(&Type, &Context)> { if let Some((t, ctx)) = self.poly_types.get(name) { Some((t, ctx)) } else if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) { @@ -1557,6 +1561,20 @@ impl Context { } } + fn rec_get_method_traits(&self, name: &Identifier) -> Option<&Type> { + if let Some(t) = self.method_traits.get(name.inspect()) { + if t.len() == 1 { + Some(&t[0]) + } else { + None + } + } else if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) { + outer.rec_get_method_traits(name) + } else { + None + } + } + fn get_gen_t_require_attr_t<'a>(&'a self, gen: &'a GenTypeObj, attr: &str) -> Option<&'a Type> { match gen.require_or_sup.typ() { Type::Record(rec) => { diff --git a/compiler/erg_compiler/context/mod.rs b/compiler/erg_compiler/context/mod.rs index 4ef22c462..44c363e2e 100644 --- a/compiler/erg_compiler/context/mod.rs +++ b/compiler/erg_compiler/context/mod.rs @@ -317,6 +317,8 @@ pub struct Context { // method definitions, if the context is a type // specializations are included and needs to be separated out pub(crate) methods_list: Vec<(ClassDefType, Context)>, + // K: method name, V: trait defines the method + pub(crate) method_traits: Dict>, /// K: method name, V: impl patch /// Provided methods can switch implementations on a scope-by-scope basis /// K: メソッド名, V: それを実装するパッチたち @@ -453,6 +455,7 @@ impl Context { super_traits: vec![], methods_list: vec![], const_param_defaults: Dict::default(), + method_traits: Dict::default(), method_impl_patches: Dict::default(), trait_impls: Dict::default(), params: params_, diff --git a/compiler/erg_compiler/context/register.rs b/compiler/erg_compiler/context/register.rs index f00d2aeb6..9a2368621 100644 --- a/compiler/erg_compiler/context/register.rs +++ b/compiler/erg_compiler/context/register.rs @@ -810,6 +810,14 @@ impl Context { ); } } + for method in ctx.decls.keys() { + if let Some(impls) = self.method_traits.get_mut(method.inspect()) { + impls.push(t.clone()); + } else { + self.method_traits + .insert(method.inspect().clone(), vec![t.clone()]); + } + } self.mono_types.insert(name.clone(), (t, ctx)); } } diff --git a/examples/trait.er b/examples/trait.er index bfb30c225..d69cf6316 100644 --- a/examples/trait.er +++ b/examples/trait.er @@ -10,6 +10,8 @@ Point3D|Point2D <: Norm|. norm|T <: Norm| x: T = x.norm() +inplicit_norm x = x.norm() + p = Point2D.new {x = 3; y = 4} print! norm(p) assert norm(p) == 25 diff --git a/examples/with.er b/examples/with.er new file mode 100644 index 000000000..5d852e3ce --- /dev/null +++ b/examples/with.er @@ -0,0 +1,2 @@ +with! open!("examples/record.er"), f => + print! f.read() From d4b6e6000e2606c1bea954457f1bbd6404095464 Mon Sep 17 00:00:00 2001 From: Shunsuke Shibayama Date: Fri, 30 Sep 2022 01:22:43 +0900 Subject: [PATCH 5/6] Update version (v0.5.5) --- Cargo.lock | 10 +++++----- Cargo.toml | 10 +++++----- compiler/erg_common/Cargo.toml | 2 +- compiler/erg_compiler/Cargo.toml | 8 ++++---- compiler/erg_parser/Cargo.toml | 4 ++-- compiler/erg_type/Cargo.toml | 6 +++--- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f0732c7b..d7dc58329 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,7 +15,7 @@ dependencies = [ [[package]] name = "erg" -version = "0.5.5-nightly.2" +version = "0.5.5" dependencies = [ "erg_common", "erg_compiler", @@ -25,14 +25,14 @@ dependencies = [ [[package]] name = "erg_common" -version = "0.5.5-nightly.2" +version = "0.5.5" dependencies = [ "atty", ] [[package]] name = "erg_compiler" -version = "0.5.5-nightly.2" +version = "0.5.5" dependencies = [ "erg_common", "erg_parser", @@ -41,14 +41,14 @@ dependencies = [ [[package]] name = "erg_parser" -version = "0.5.5-nightly.2" +version = "0.5.5" dependencies = [ "erg_common", ] [[package]] name = "erg_type" -version = "0.5.5-nightly.2" +version = "0.5.5" dependencies = [ "erg_common", "erg_parser", diff --git a/Cargo.toml b/Cargo.toml index 51ab6e3db..430bd54b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "erg" -version = "0.5.5-nightly.2" +version = "0.5.5" description = "The Erg programming language" authors = ["erg-lang team "] license = "MIT OR Apache-2.0" @@ -46,10 +46,10 @@ traditional_chinese = [ ] [dependencies] -erg_common = { version = "0.5.5-nightly.2", path = "./compiler/erg_common" } -erg_parser = { version = "0.5.5-nightly.2", path = "./compiler/erg_parser" } -erg_compiler = { version = "0.5.5-nightly.2", path = "./compiler/erg_compiler" } -erg_type = { version = "0.5.5-nightly.2", path = "./compiler/erg_type" } +erg_common = { version = "0.5.5", path = "./compiler/erg_common" } +erg_parser = { version = "0.5.5", path = "./compiler/erg_parser" } +erg_compiler = { version = "0.5.5", path = "./compiler/erg_compiler" } +erg_type = { version = "0.5.5", path = "./compiler/erg_type" } # [workspace] # member = ["cm", "dyne"] diff --git a/compiler/erg_common/Cargo.toml b/compiler/erg_common/Cargo.toml index ea11117cb..2b8d5ac50 100644 --- a/compiler/erg_common/Cargo.toml +++ b/compiler/erg_common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "erg_common" -version = "0.5.5-nightly.2" +version = "0.5.5" description = "A common components library of Erg" authors = ["erg-lang team "] license = "MIT OR Apache-2.0" diff --git a/compiler/erg_compiler/Cargo.toml b/compiler/erg_compiler/Cargo.toml index b23e79493..7efaae39f 100644 --- a/compiler/erg_compiler/Cargo.toml +++ b/compiler/erg_compiler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "erg_compiler" -version = "0.5.5-nightly.2" +version = "0.5.5" description = "Centimetre: the Erg compiler" authors = ["erg-lang team "] license = "MIT OR Apache-2.0" @@ -17,9 +17,9 @@ simplified_chinese = [ "erg_common/simplified_chinese", "erg_parser/simplified_c traditional_chinese = [ "erg_common/traditional_chinese", "erg_parser/traditional_chinese", "erg_type/traditional_chinese" ] [dependencies] -erg_common = { version = "0.5.5-nightly.2", path = "../erg_common" } -erg_parser = { version = "0.5.5-nightly.2", path = "../erg_parser" } -erg_type = { version = "0.5.5-nightly.2", path = "../erg_type" } +erg_common = { version = "0.5.5", path = "../erg_common" } +erg_parser = { version = "0.5.5", path = "../erg_parser" } +erg_type = { version = "0.5.5", path = "../erg_type" } [lib] path = "lib.rs" diff --git a/compiler/erg_parser/Cargo.toml b/compiler/erg_parser/Cargo.toml index d38f93359..a6e4fc075 100644 --- a/compiler/erg_parser/Cargo.toml +++ b/compiler/erg_parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "erg_parser" -version = "0.5.5-nightly.2" +version = "0.5.5" description = "The Erg parser" authors = ["erg-lang team "] license = "MIT OR Apache-2.0" @@ -16,7 +16,7 @@ simplified_chinese = [ "erg_common/simplified_chinese" ] traditional_chinese = [ "erg_common/traditional_chinese" ] [dependencies] -erg_common = { version = "0.5.5-nightly.2", path = "../erg_common" } +erg_common = { version = "0.5.5", path = "../erg_common" } [lib] path = "lib.rs" diff --git a/compiler/erg_type/Cargo.toml b/compiler/erg_type/Cargo.toml index 5faa77bb5..78a29372c 100644 --- a/compiler/erg_type/Cargo.toml +++ b/compiler/erg_type/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "erg_type" -version = "0.5.5-nightly.2" +version = "0.5.5" description = "APIs for Erg types" authors = ["erg-lang team "] license = "MIT OR Apache-2.0" @@ -18,8 +18,8 @@ simplified_chinese = [ "erg_common/simplified_chinese" ] traditional_chinese = [ "erg_common/traditional_chinese" ] [dependencies] -erg_common = { version = "0.5.5-nightly.2", path = "../erg_common" } -erg_parser = { version = "0.5.5-nightly.2", path = "../erg_parser" } +erg_common = { version = "0.5.5", path = "../erg_common" } +erg_parser = { version = "0.5.5", path = "../erg_parser" } [lib] path = "lib.rs" From 8b535a3ae090490ed831d366ffa8dc6ba44f7302 Mon Sep 17 00:00:00 2001 From: Shunsuke Shibayama Date: Fri, 30 Sep 2022 02:14:58 +0900 Subject: [PATCH 6/6] Update codegen.rs --- compiler/erg_compiler/codegen.rs | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/compiler/erg_compiler/codegen.rs b/compiler/erg_compiler/codegen.rs index 1fa98ac81..db211fca5 100644 --- a/compiler/erg_compiler/codegen.rs +++ b/compiler/erg_compiler/codegen.rs @@ -1369,7 +1369,7 @@ impl CodeGenerator { // push __exit__, __enter__() to the stack self.stack_inc_n(2); let lambda_line = lambda.body.last().unwrap().ln_begin().unwrap_or(0); - self.emit_frameless_block(lambda.body, params); + self.emit_with_block(lambda.body, params); let stash = Identifier::private_with_line(Str::from(fresh_varname()), lambda_line); self.emit_store_instr(stash.clone(), Name); self.write_instr(POP_BLOCK); @@ -1383,10 +1383,10 @@ impl CodeGenerator { self.stack_inc(); self.write_instr(CALL_FUNCTION); self.write_arg(3); - self.stack_dec_n(3 - 1); + self.stack_dec_n((1 + 3) - 1); self.emit_pop_top(); - self.emit_load_const(ValueObj::None); - self.write_instr(RETURN_VALUE); + let idx_jump_forward = self.cur_block().lasti; + self.write_instr(JUMP_FORWARD); self.write_arg(0); self.edit_code( idx_setup_with + 1, @@ -1400,11 +1400,13 @@ impl CodeGenerator { self.write_instr(RERAISE); self.write_arg(1); self.edit_code(idx_pop_jump_if_true + 1, self.cur_block().lasti / 2); - self.emit_pop_top(); - self.emit_pop_top(); + // self.emit_pop_top(); + // self.emit_pop_top(); self.emit_pop_top(); self.write_instr(POP_EXCEPT); self.write_arg(0); + let idx_end = self.cur_block().lasti; + self.edit_code(idx_jump_forward + 1, (idx_end - idx_jump_forward - 2) / 2); self.emit_load_name_instr(stash); } @@ -1725,6 +1727,24 @@ impl CodeGenerator { self.cancel_pop_top(); } + fn emit_with_block(&mut self, block: Block, params: Vec) { + log!(info "entered {}", fn_name!()); + let line = block.ln_begin().unwrap_or(0); + for param in params { + self.emit_store_instr( + Identifier::public_with_line(Token::dummy(), param, line), + Name, + ); + } + for expr in block.into_iter() { + self.emit_expr(expr); + if self.cur_block().stack_len != 0 { + self.emit_pop_top(); + } + } + self.cancel_pop_top(); + } + fn emit_class_block(&mut self, class: ClassDef) -> CodeObj { log!(info "entered {}", fn_name!()); let name = class.sig.ident().inspect().clone();