mirror of
https://github.com/mtshiba/pylyzer.git
synced 2025-08-04 22:38:02 +00:00
Support operator checks for user-defined classes
This commit is contained in:
parent
f360c2c763
commit
4b3ff53295
5 changed files with 39 additions and 16 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -253,7 +253,7 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
|||
[[package]]
|
||||
name = "els"
|
||||
version = "0.1.18"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=main#23cbbe30719af994dc299438f9b35acef4ddc19c"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=py-structural#5cddba369e9124f846348e0a690d3b84b252366a"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"erg_compiler",
|
||||
|
@ -274,7 +274,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "erg_common"
|
||||
version = "0.6.6"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=main#23cbbe30719af994dc299438f9b35acef4ddc19c"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=py-structural#5cddba369e9124f846348e0a690d3b84b252366a"
|
||||
dependencies = [
|
||||
"backtrace-on-stack-overflow",
|
||||
"hermit-abi",
|
||||
|
@ -285,7 +285,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "erg_compiler"
|
||||
version = "0.6.6"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=main#23cbbe30719af994dc299438f9b35acef4ddc19c"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=py-structural#5cddba369e9124f846348e0a690d3b84b252366a"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"erg_parser",
|
||||
|
@ -294,7 +294,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "erg_parser"
|
||||
version = "0.6.6"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=main#23cbbe30719af994dc299438f9b35acef4ddc19c"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=py-structural#5cddba369e9124f846348e0a690d3b84b252366a"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"unicode-xid 0.2.4",
|
||||
|
@ -916,9 +916,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.107"
|
||||
version = "1.0.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
|
||||
checksum = "d56e159d99e6c2b93995d171050271edb50ecc5288fbc7cc17de8fdce4e58c14"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
@ -26,9 +26,9 @@ repository = "https://github.com/mtshiba/pylyzer"
|
|||
# erg_compiler = { version = "0.6.5-nightly.1", features = ["py_compatible", "els"] }
|
||||
# els = { version = "0.1.17-nightly.1", features = ["py_compatible"] }
|
||||
rustpython-parser = "0.1.2"
|
||||
erg_compiler = { git = "https://github.com/erg-lang/erg", branch = "main", features = ["py_compatible", "els"] }
|
||||
erg_common = { git = "https://github.com/erg-lang/erg", branch = "main", features = ["py_compatible", "els"] }
|
||||
els = { git = "https://github.com/erg-lang/erg", branch = "main", features = ["py_compatible"] }
|
||||
erg_compiler = { git = "https://github.com/erg-lang/erg", branch = "py-structural", features = ["py_compatible", "els"] }
|
||||
erg_common = { git = "https://github.com/erg-lang/erg", branch = "py-structural", features = ["py_compatible", "els"] }
|
||||
els = { git = "https://github.com/erg-lang/erg", branch = "py-structural", features = ["py_compatible"] }
|
||||
|
||||
[features]
|
||||
debug = ["erg_compiler/debug", "erg_common/debug", "py2erg/debug"]
|
||||
|
|
|
@ -843,7 +843,8 @@ impl ASTConverter {
|
|||
// self.y = y
|
||||
// self.z = z
|
||||
// ↓
|
||||
// {x: Int, y: Int, z: Never}, .__call__(x: Int, y: Int, z: Obj): Self = .unreachable()
|
||||
// requirement : {x: Int, y: Int, z: Never}
|
||||
// returns : .__call__(x: Int, y: Int, z: Obj): Self = .unreachable()
|
||||
fn extract_init(&mut self, base_type: &mut Option<Expr>, init_def: Def) -> Option<Def> {
|
||||
self.check_init_sig(&init_def.sig)?;
|
||||
let l_brace = Token::new(
|
||||
|
@ -988,8 +989,8 @@ impl ASTConverter {
|
|||
.map(|id| &id.inspect()[..] == "__init__")
|
||||
.unwrap_or(false)
|
||||
{
|
||||
if let Some(init_def) = self.extract_init(&mut base_type, def) {
|
||||
attrs.push(ClassAttr::Def(init_def));
|
||||
if let Some(call_def) = self.extract_init(&mut base_type, def) {
|
||||
attrs.insert(0, ClassAttr::Def(call_def));
|
||||
init_is_defined = true;
|
||||
}
|
||||
} else {
|
||||
|
@ -1041,7 +1042,7 @@ impl ASTConverter {
|
|||
}
|
||||
}
|
||||
if !init_is_defined {
|
||||
attrs.push(ClassAttr::Def(self.gen_default_init(0)));
|
||||
attrs.insert(0, ClassAttr::Def(self.gen_default_init(0)));
|
||||
}
|
||||
(base_type, ClassAttrs::new(attrs))
|
||||
}
|
||||
|
|
|
@ -11,19 +11,33 @@ class C:
|
|||
def __init__(self, x: int, y): # y: Obj
|
||||
self.x = x
|
||||
self.y = y # y: Never
|
||||
def __add__(self, other: C):
|
||||
return C(self.x + other.x, self.y + other.y)
|
||||
def method(self):
|
||||
return self.x
|
||||
|
||||
c = C(1, 2)
|
||||
assert c.x == 1
|
||||
assert c.y == 2 # OK, c.y == "a" is also OK
|
||||
# OK, c.y == "a" is also OK (cause the checker doesn't know the type of C.y)
|
||||
assert c.y == 2
|
||||
assert c.z == 3 # ERR
|
||||
d = c + c
|
||||
assert d.x == 2
|
||||
assert d.x == "a" # ERR
|
||||
a = c.method() # OK
|
||||
_: int = a + 1
|
||||
b = C("a").method() # ERR
|
||||
|
||||
class D:
|
||||
c: int
|
||||
def __add__(self, other: D):
|
||||
return D(self.c + other.c)
|
||||
def __sub__(self, other: C):
|
||||
return D(self.c - other.x)
|
||||
def __init__(self, c):
|
||||
self.c = c
|
||||
|
||||
c1 = D(1).c + 1
|
||||
d = D(1) + D(2)
|
||||
err = C(1, 2) + D(1) # ERR
|
||||
ok = D(1) - C(1, 2) # OK
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use erg_common::config::{ErgConfig, Input};
|
||||
use erg_common::spawn::exec_new_thread;
|
||||
use erg_common::traits::Stream;
|
||||
use erg_compiler::artifact::{CompleteArtifact, IncompleteArtifact};
|
||||
use pylyzer::PythonAnalyzer;
|
||||
|
@ -15,7 +16,8 @@ pub fn exec_analyzer(file_path: &'static str) -> Result<CompleteArtifact, Incomp
|
|||
analyzer.analyze(py_code, "exec")
|
||||
}
|
||||
|
||||
pub fn expect(file_path: &'static str, warns: usize, errors: usize) {
|
||||
fn _expect(file_path: &'static str, warns: usize, errors: usize) {
|
||||
println!("Testing {file_path} ...");
|
||||
match exec_analyzer(file_path) {
|
||||
Ok(artifact) => {
|
||||
assert_eq!(artifact.warns.len(), warns);
|
||||
|
@ -28,6 +30,12 @@ pub fn expect(file_path: &'static str, warns: usize, errors: usize) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn expect(file_path: &'static str, warns: usize, errors: usize) {
|
||||
exec_new_thread(move || {
|
||||
_expect(file_path, warns, errors);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exec_test() {
|
||||
expect("tests/test.py", 0, 10);
|
||||
|
@ -50,7 +58,7 @@ fn exec_func() {
|
|||
|
||||
#[test]
|
||||
fn exec_class() {
|
||||
expect("tests/class.py", 0, 1);
|
||||
expect("tests/class.py", 0, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue