diff --git a/crates/py2erg/convert.rs b/crates/py2erg/convert.rs index 246e9e8..5a7bfbd 100644 --- a/crates/py2erg/convert.rs +++ b/crates/py2erg/convert.rs @@ -525,12 +525,12 @@ impl ASTConverter { Block::new(new_block) } - fn find_init_self(&mut self, init_def: &Def) { - match &init_def.sig { + fn check_init_sig(&mut self, sig: &Signature) -> Option<()> { + match sig { Signature::Subr(subr) => { if let Some(first) = subr.params.non_defaults.get(0) { if first.inspect().map(|s| &s[..]) == Some("self") { - return; + return Some(()); } } self.errs.push(self_not_found_error( @@ -538,6 +538,7 @@ impl ASTConverter { subr.loc(), self.namespace.join("."), )); + Some(()) } Signature::Var(var) => { self.errs.push(init_var_error( @@ -545,6 +546,7 @@ impl ASTConverter { var.loc(), self.namespace.join("."), )); + None } } } @@ -555,8 +557,8 @@ impl ASTConverter { // self.z = z // ↓ // {x: Int, y: Int, z: Never}, .__call__(x: Int, y: Int, z: Obj): Self = .unreachable() - fn extract_init(&mut self, init_def: Def) -> (Expr, Def) { - self.find_init_self(&init_def); + fn extract_init(&mut self, init_def: Def) -> Option<(Expr, Def)> { + self.check_init_sig(&init_def.sig)?; let l_brace = Token::new(TokenKind::LBrace, "{", init_def.ln_begin().unwrap_or(0), init_def.col_begin().unwrap_or(0)); let r_brace = Token::new(TokenKind::RBrace, "}", init_def.ln_end().unwrap_or(0), init_def.col_end().unwrap_or(0)); let Signature::Subr(sig) = init_def.sig else { unreachable!() }; @@ -601,7 +603,7 @@ impl ASTConverter { let body = Expr::Accessor(Accessor::Ident(unreachable_acc)).call_expr(Args::empty()); let body = DefBody::new(EQUAL, Block::new(vec![body]), DefId(0)); let def = Def::new(sig, body); - (Expr::Record(record), def) + Some((Expr::Record(record), def)) } fn gen_default_init(&self, line: usize) -> Def { @@ -624,11 +626,12 @@ impl ASTConverter { let chunk = self.convert_statement(stmt, true); match chunk { Expr::Def(def) => { - if def.is_subr() && &def.sig.ident().unwrap().inspect()[..] == "__init__" { - let (base_t, init_def) = self.extract_init(def); - base_type = Some(base_t); - attrs.push(ClassAttr::Def(init_def)); - init_is_defined = true; + if def.sig.ident().map(|id| &id.inspect()[..] == "__init__").unwrap_or(false) { + if let Some((base_t, init_def)) = self.extract_init(def) { + base_type = Some(base_t); + attrs.push(ClassAttr::Def(init_def)); + init_is_defined = true; + } } else { attrs.push(ClassAttr::Def(def)); } @@ -833,13 +836,13 @@ impl ASTConverter { } => { // if reassigning of a function referenced by other functions is occurred, it is an error if self.get_name(&name).map(|info| info.defined_times > 0 && !info.referenced.difference(&set!{name.clone()}).is_empty()).unwrap_or(false) { - let warn = reassign_func_error( + let err = reassign_func_error( self.cfg.input.clone(), pyloc_to_ergloc(stmt.location, name.len()), self.namespace.join("."), &name ); - self.warns.push(warn); + self.errs.push(err); Expr::Dummy(Dummy::empty()) } else { let decos = decorator_list.into_iter().map(|ex| Decorator(self.convert_expr(ex))).collect::>(); diff --git a/crates/py2erg/error.rs b/crates/py2erg/error.rs index f883f97..a683ef8 100644 --- a/crates/py2erg/error.rs +++ b/crates/py2erg/error.rs @@ -59,10 +59,10 @@ pub(crate) fn init_var_error( ErrorCore::new( vec![SubMessage::only_loc(loc)], switch_lang!( - "japanese" => format!("__init__はメソッドです。メンバ変数として宣言することはできません"), - "simplified_chinese" => format!("__init__是方法。不能声明为变量"), + "japanese" => format!("`__init__`はメソッドです。メンバ変数として宣言するべきではありません"), + "simplified_chinese" => format!("__init__是方法。不能宣告为变量"), "traditional_chinese" => format!("__init__是方法。不能宣告為變量"), - "english" => format!("__init__ is a method. It cannot be declared as a member variable"), + "english" => format!("`__init__` should be a method. It should not be defined as a member variable"), ), 3, ErrorKind::NameError, diff --git a/tests/e0001.py b/tests/errors.py similarity index 55% rename from tests/e0001.py rename to tests/errors.py index 5987f77..4e46407 100644 --- a/tests/e0001.py +++ b/tests/errors.py @@ -1,3 +1,5 @@ +# E0001 + def a(): return 1 def a(): return "a" # OK @@ -7,3 +9,15 @@ def g(): return f() def f(): return 1 def f(): return "a" # E0001: Reassignment of a function referenced by other functions + +# E0002 + +class C: + def __init__(self): pass # OK +class C: + def __init__(a): pass # ERR + +# E0003 + +class C: + __init__ = 1 # ERR diff --git a/tests/test.rs b/tests/test.rs index 09982ec..016f5e4 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -46,6 +46,11 @@ fn exec_class() { } #[test] -fn exec_e0001() { - expect("tests/e0001.py", 1, 0); +fn exec_errors() { + expect("tests/errors.py", 0, 3); +} + +#[test] +fn exec_warns() { + expect("tests/warns.py", 2, 0); } diff --git a/tests/warns.py b/tests/warns.py new file mode 100644 index 0000000..3a3605f --- /dev/null +++ b/tests/warns.py @@ -0,0 +1,9 @@ +# W0188: unused value + +1 # Warn + +def f(): return "a" +f() # Warn + +def f(): return None +f() # OK