diff --git a/compiler/erg_common/dict.rs b/compiler/erg_common/dict.rs index 98920f17..6785e9d4 100644 --- a/compiler/erg_common/dict.rs +++ b/compiler/erg_common/dict.rs @@ -153,6 +153,14 @@ impl Dict { self.dict.get_mut(k) } + pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> + where + K: Borrow, + Q: Hash + Eq, + { + self.dict.get_key_value(k) + } + #[inline] pub fn contains_key(&self, k: &Q) -> bool where diff --git a/compiler/erg_compiler/codegen.rs b/compiler/erg_compiler/codegen.rs index 641357e3..b17b2720 100644 --- a/compiler/erg_compiler/codegen.rs +++ b/compiler/erg_compiler/codegen.rs @@ -202,7 +202,7 @@ fn convert_to_python_attr(class: &str, uniq_obj_name: Option<&str>, name: Str) - ("Array!", _, "push!") => Str::ever("append"), ("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Real") => Str::ever("real"), ("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Imag") => Str::ever("imag"), - (_, _, "new" | "__new__") => Str::ever("__call__"), + (_, _, "__new__") => Str::ever("__call__"), ("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/inquire.rs b/compiler/erg_compiler/context/inquire.rs index 012dc4ee..d0a33aed 100644 --- a/compiler/erg_compiler/context/inquire.rs +++ b/compiler/erg_compiler/context/inquire.rs @@ -80,6 +80,10 @@ impl Context { }) } + pub(crate) fn get_local_kv(&self, name: &str) -> Option<(&VarName, &VarInfo)> { + self.locals.get_key_value(name) + } + fn get_context( &self, obj: &hir::Expr, diff --git a/compiler/erg_compiler/context/mod.rs b/compiler/erg_compiler/context/mod.rs index 923955a1..038f0cfa 100644 --- a/compiler/erg_compiler/context/mod.rs +++ b/compiler/erg_compiler/context/mod.rs @@ -490,6 +490,20 @@ impl Context { Self::poly_class(name, vec![], super_classes, super_traits, level) } + #[inline] + pub fn methods>(name: S, level: usize) -> Self { + Self::with_capacity( + name.into(), + ContextKind::MethodDefs, + vec![], + None, + vec![], + vec![], + 2, + level, + ) + } + #[inline] pub fn poly_patch>( name: S, diff --git a/compiler/erg_compiler/context/register.rs b/compiler/erg_compiler/context/register.rs index 02496b44..4727933b 100644 --- a/compiler/erg_compiler/context/register.rs +++ b/compiler/erg_compiler/context/register.rs @@ -508,6 +508,7 @@ impl Context { Ok(()) } + /// e.g. .new fn register_auto_impl( &mut self, name: &'static str, @@ -524,6 +525,23 @@ impl Context { } } + /// e.g. ::__new__ + fn register_fixed_auto_impl( + &mut self, + name: &'static str, + t: Type, + muty: Mutability, + vis: Visibility, + ) { + let name = VarName::from_static(name); + if self.locals.get(&name).is_some() { + panic!("already registered: {name}"); + } else { + self.locals + .insert(name, VarInfo::new(t, muty, vis, VarKind::FixedAuto, None)); + } + } + fn _register_gen_decl(&mut self, name: VarName, t: Type, vis: Visibility) { if self.decls.get(&name).is_some() { panic!("already registered: {name}"); @@ -577,11 +595,13 @@ impl Context { if gen.t.is_monomorphic() { let super_traits = gen.impls.iter().map(|to| to.typ().clone()).collect(); let mut ctx = Self::mono_class(gen.t.name(), vec![], super_traits, self.level); + let mut methods = Self::methods(gen.t.name(), self.level); let require = gen.require_or_sup.typ().clone(); let new_t = func1(require, gen.t.clone()); - ctx.register_auto_impl("__new__", new_t.clone(), Immutable, Private); + methods.register_fixed_auto_impl("__new__", new_t.clone(), Immutable, Private); // 必要なら、ユーザーが独自に上書きする - ctx.register_auto_impl("new", new_t, Immutable, Public); + methods.register_auto_impl("new", new_t, Immutable, Public); + ctx.method_defs.push((gen.t.clone(), methods)); self.register_gen_mono_type(gen, ctx, Const); } else { todo!() @@ -593,6 +613,7 @@ impl Context { let super_traits = gen.impls.iter().map(|to| to.typ().clone()).collect(); let mut ctx = Self::mono_class(gen.t.name(), super_classes, super_traits, self.level); + let mut methods = Self::methods(gen.t.name(), self.level); if let Some(sup) = self.rec_get_const_obj(&gen.require_or_sup.typ().name()) { let sup = enum_unwrap!(sup, ValueObj::Type); let param_t = match sup { @@ -607,9 +628,15 @@ impl Context { param_t.clone() }; let new_t = func1(param_t, gen.t.clone()); - ctx.register_auto_impl("__new__", new_t.clone(), Immutable, Private); + methods.register_fixed_auto_impl( + "__new__", + new_t.clone(), + Immutable, + Private, + ); // 必要なら、ユーザーが独自に上書きする - ctx.register_auto_impl("new", new_t, Immutable, Public); + methods.register_auto_impl("new", new_t, Immutable, Public); + ctx.method_defs.push((gen.t.clone(), methods)); self.register_gen_mono_type(gen, ctx, Const); } else { todo!("super class not found") diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index 2fffd1aa..55544d16 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -331,6 +331,30 @@ impl TyCheckError { ) } + pub fn duplicate_definition_error( + errno: usize, + loc: Location, + caused_by: Str, + name: &str, + ) -> Self { + let name = readable_name(name); + Self::new( + ErrorCore::new( + errno, + NameError, + loc, + switch_lang!( + "japanese" => format!("{name}は既に定義されています"), + "simplified_chinese" => format!("{name}已定义"), + "traditional_chinese" => format!("{name}已定義"), + "english" => format!("{name} is already defined"), + ), + Option::::None, + ), + caused_by, + ) + } + pub fn violate_decl_error( errno: usize, loc: Location, diff --git a/compiler/erg_compiler/link.rs b/compiler/erg_compiler/link.rs index 2ddbbba8..cb5deee2 100644 --- a/compiler/erg_compiler/link.rs +++ b/compiler/erg_compiler/link.rs @@ -50,12 +50,12 @@ impl Linker { Expr::Methods(methods) => match &methods.class { TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(simple)) => { if let Some(pos) = self.def_root_pos_map.get(simple.name.inspect()) { - let mut type_def = match new.remove(*pos) { - Expr::ClassDef(type_def) => type_def, + let mut class_def = match new.remove(*pos) { + Expr::ClassDef(class_def) => class_def, _ => unreachable!(), }; - type_def.methods_list.push(methods); - new.insert(*pos, Expr::ClassDef(type_def)); + class_def.methods_list.push(methods); + new.insert(*pos, Expr::ClassDef(class_def)); } else { log!("{}", simple.name.inspect()); log!("{}", self.def_root_pos_map); diff --git a/compiler/erg_compiler/lower.rs b/compiler/erg_compiler/lower.rs index e777cfdf..a6fd08e2 100644 --- a/compiler/erg_compiler/lower.rs +++ b/compiler/erg_compiler/lower.rs @@ -570,10 +570,33 @@ impl ASTLowerer { } } match self.ctx.pop() { - Ok(ctx) => { - self.check_override(&class, &ctx); + Ok(methods) => { + self.check_override(&class, &methods); if let Some((_, class_root)) = self.ctx.rec_get_mut_nominal_type_ctx(&class) { - class_root.method_defs.push((class, ctx)); + for (newly_defined_name, _vi) in methods.locals.iter() { + for (_, already_defined_methods) in class_root.method_defs.iter_mut() { + // TODO: 特殊化なら同じ名前でもOK + // TODO: 定義のメソッドもエラー表示 + if let Some((_already_defined_name, already_defined_vi)) = + already_defined_methods + .get_local_kv(&newly_defined_name.inspect()) + { + if already_defined_vi.kind != VarKind::Auto { + self.errs.push(LowerError::duplicate_definition_error( + line!() as usize, + newly_defined_name.loc(), + methods.name.clone(), + newly_defined_name.inspect(), + )); + } else { + already_defined_methods + .locals + .remove(&newly_defined_name.inspect()[..]); + } + } + } + } + class_root.method_defs.push((class, methods)); } else { todo!() } diff --git a/compiler/erg_compiler/varinfo.rs b/compiler/erg_compiler/varinfo.rs index e88339c1..5bb4fb11 100644 --- a/compiler/erg_compiler/varinfo.rs +++ b/compiler/erg_compiler/varinfo.rs @@ -68,6 +68,7 @@ pub enum VarKind { default: DefaultInfo, }, Auto, + FixedAuto, DoesNotExist, Builtin, }