mirror of https://github.com/mtshiba/pylyzer
feat: support `Callable/Iterable`
This commit is contained in:
parent
b8de76f8a9
commit
12cdb09559
|
|
@ -252,9 +252,9 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "els"
|
name = "els"
|
||||||
version = "0.1.24-nightly.4"
|
version = "0.1.24-nightly.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f74cdce8d05df8b4a6090cc892e34a30ab6880f5ed8786e9346fe4d4fb4c47d5"
|
checksum = "3db3f0318812d7401d51a3232f256faaa15963f30f4bf7bc07dc8bc73b849353"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"erg_common",
|
"erg_common",
|
||||||
"erg_compiler",
|
"erg_compiler",
|
||||||
|
|
@ -274,9 +274,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "erg_common"
|
name = "erg_common"
|
||||||
version = "0.6.12-nightly.4"
|
version = "0.6.12-nightly.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "07cc57d02fe5520b0f0a42d30be2604edafa71a35074a35f579f2ca91533d965"
|
checksum = "8c34723b8e8f53e11205330924f36425d52b2ebae66a5d45e889fb83a01be4fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace-on-stack-overflow",
|
"backtrace-on-stack-overflow",
|
||||||
"hermit-abi",
|
"hermit-abi",
|
||||||
|
|
@ -286,9 +286,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "erg_compiler"
|
name = "erg_compiler"
|
||||||
version = "0.6.12-nightly.4"
|
version = "0.6.12-nightly.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "101a854704b5bda829d4fa6005d590b2f426ce6624b8361118b4949c7d90c859"
|
checksum = "beef1255c0fe34d84892d6b3eecd4506a77ba71d24a8b143795f1c5b2e4f6877"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"erg_common",
|
"erg_common",
|
||||||
"erg_parser",
|
"erg_parser",
|
||||||
|
|
@ -296,9 +296,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "erg_parser"
|
name = "erg_parser"
|
||||||
version = "0.6.12-nightly.4"
|
version = "0.6.12-nightly.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "43fe0229517462ba79374a8eb1b16a183f0854744af6d4ebfcd4b2ff05539121"
|
checksum = "a16c93aca8cc69dd920dd3a6fb0c6ab9054bdfe3e46ada0ea89dce8896617296"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"erg_common",
|
"erg_common",
|
||||||
"unicode-xid 0.2.4",
|
"unicode-xid 0.2.4",
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,9 @@ edition = "2021"
|
||||||
repository = "https://github.com/mtshiba/pylyzer"
|
repository = "https://github.com/mtshiba/pylyzer"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
erg_common = { version = "0.6.12-nightly.4", features = ["py_compat", "els"] }
|
erg_common = { version = "0.6.12-nightly.6", features = ["py_compat", "els"] }
|
||||||
erg_compiler = { version = "0.6.12-nightly.4", features = ["py_compat", "els"] }
|
erg_compiler = { version = "0.6.12-nightly.6", features = ["py_compat", "els"] }
|
||||||
els = { version = "0.1.24-nightly.4", features = ["py_compat"] }
|
els = { version = "0.1.24-nightly.6", features = ["py_compat"] }
|
||||||
rustpython-parser = "0.1.2"
|
rustpython-parser = "0.1.2"
|
||||||
# erg_compiler = { git = "https://github.com/erg-lang/erg", branch = "main", features = ["py_compat", "els"] }
|
# erg_compiler = { git = "https://github.com/erg-lang/erg", branch = "main", features = ["py_compat", "els"] }
|
||||||
# erg_common = { git = "https://github.com/erg-lang/erg", branch = "main", features = ["py_compat", "els"] }
|
# erg_common = { git = "https://github.com/erg-lang/erg", branch = "main", features = ["py_compat", "els"] }
|
||||||
|
|
|
||||||
23
README.md
23
README.md
|
|
@ -99,23 +99,28 @@ pylyzer converts Python ASTs to Erg ASTs and passes them to Erg's type checker.
|
||||||
* [x] builtin modules resolving (partially)
|
* [x] builtin modules resolving (partially)
|
||||||
* [x] local scripts resolving
|
* [x] local scripts resolving
|
||||||
* [ ] local packages resolving
|
* [ ] local packages resolving
|
||||||
* [ ] compound type checking
|
* [x] collection types
|
||||||
* [x] `Union`
|
|
||||||
* [x] `Optional`
|
|
||||||
* [x] `list`
|
* [x] `list`
|
||||||
* [x] `dict`
|
* [x] `dict`
|
||||||
* [x] `tuple`
|
* [x] `tuple`
|
||||||
|
* [ ] `typing`
|
||||||
|
* [x] `Union`
|
||||||
|
* [x] `Optional`
|
||||||
* [x] `Literal`
|
* [x] `Literal`
|
||||||
|
* [x] `Callable`
|
||||||
* [ ] `TypedDict`
|
* [ ] `TypedDict`
|
||||||
|
* [ ] type variable (`TypeVar`, `Generic`)
|
||||||
|
* [ ] `Protocol`
|
||||||
|
* [ ] `Final`
|
||||||
|
* [ ] `Annotated`
|
||||||
|
* [ ] `TypeAlias`
|
||||||
|
* [ ] type guard (`TypeGuard`)
|
||||||
|
* [ ] others
|
||||||
|
* `collections.abc`
|
||||||
|
* [x] `Iterable`
|
||||||
* [ ] others
|
* [ ] others
|
||||||
* [ ] type variable (`TypeVar`, `Generic`)
|
|
||||||
* [ ] `Protocol`
|
|
||||||
* [ ] `Final`
|
|
||||||
* [ ] `Annotated`
|
|
||||||
* [ ] `TypeAlias`
|
|
||||||
* [x] type assertion (`typing.cast`)
|
* [x] type assertion (`typing.cast`)
|
||||||
* [x] type narrowing (`is`, `isinstance`)
|
* [x] type narrowing (`is`, `isinstance`)
|
||||||
* [ ] type guard (`TypeGuard`)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use erg_compiler::erg_parser::ast::{
|
||||||
NormalTuple, ParamPattern, Params, PosArg, PreDeclTypeSpec, ReDef, Record, RecordAttrs, Set,
|
NormalTuple, ParamPattern, Params, PosArg, PreDeclTypeSpec, ReDef, Record, RecordAttrs, Set,
|
||||||
Signature, SubrSignature, Tuple, TypeAscription, TypeBoundSpecs, TypeSpec,
|
Signature, SubrSignature, Tuple, TypeAscription, TypeBoundSpecs, TypeSpec,
|
||||||
TypeSpecWithOp, UnaryOp, VarName, VarPattern, VarRecordAttr, VarRecordAttrs, VarRecordPattern,
|
TypeSpecWithOp, UnaryOp, VarName, VarPattern, VarRecordAttr, VarRecordAttrs, VarRecordPattern,
|
||||||
VarSignature, VisModifierSpec, ConstPosArg, ConstDict, ConstKeyValue, TupleTypeSpec,
|
VarSignature, VisModifierSpec, ConstPosArg, ConstDict, ConstKeyValue, TupleTypeSpec, SubrTypeSpec, ParamTySpec, ConstAttribute,
|
||||||
};
|
};
|
||||||
use erg_compiler::erg_parser::desugar::Desugarer;
|
use erg_compiler::erg_parser::desugar::Desugarer;
|
||||||
use erg_compiler::erg_parser::token::{Token, TokenKind, AS, DOT, EQUAL};
|
use erg_compiler::erg_parser::token::{Token, TokenKind, AS, DOT, EQUAL};
|
||||||
|
|
@ -29,6 +29,8 @@ use crate::ast_util::length;
|
||||||
use crate::clone::clone_loc_expr;
|
use crate::clone::clone_loc_expr;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
|
|
||||||
|
pub const ARROW: Token = Token::dummy(TokenKind::FuncArrow, "->");
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum NameKind {
|
pub enum NameKind {
|
||||||
Variable,
|
Variable,
|
||||||
|
|
@ -550,6 +552,50 @@ impl ASTConverter {
|
||||||
let elems = ConstArgs::new(elems, None, vec![], None);
|
let elems = ConstArgs::new(elems, None, vec![], None);
|
||||||
TypeSpec::Enum(elems)
|
TypeSpec::Enum(elems)
|
||||||
}
|
}
|
||||||
|
// TODO: distinguish from collections.abc.Callable
|
||||||
|
"Callable" => {
|
||||||
|
let ExpressionType::Tuple { mut elements } = args.node else {
|
||||||
|
return Self::gen_dummy_type_spec(args.location);
|
||||||
|
};
|
||||||
|
let params = elements.remove(0);
|
||||||
|
let mut non_defaults = vec![];
|
||||||
|
match params.node {
|
||||||
|
ExpressionType::List { elements } => {
|
||||||
|
for param in elements.into_iter() {
|
||||||
|
let t_spec = self.convert_type_spec(param);
|
||||||
|
non_defaults.push(ParamTySpec::anonymous(t_spec));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
let err = CompileError::syntax_error(
|
||||||
|
self.cfg.input.clone(),
|
||||||
|
line!() as usize,
|
||||||
|
pyloc_to_ergloc(params.location, length(&other)),
|
||||||
|
self.cur_namespace(),
|
||||||
|
"Expected a list of parameters".into(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
self.errs.push(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let ret = self.convert_type_spec(elements.remove(0));
|
||||||
|
TypeSpec::Subr(SubrTypeSpec::new(TypeBoundSpecs::empty(), None, non_defaults, None, vec![], ARROW, ret))
|
||||||
|
}
|
||||||
|
"Iterable" => {
|
||||||
|
let elem_t = self.convert_expr(args);
|
||||||
|
let elem_t = match Parser::validate_const_expr(elem_t) {
|
||||||
|
Ok(elem_t) => elem_t,
|
||||||
|
Err(err) => {
|
||||||
|
let err = CompileError::new(err.into(), self.cfg.input.clone(), self.cur_namespace());
|
||||||
|
self.errs.push(err);
|
||||||
|
ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("Obj".into())))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let elem_t = ConstPosArg::new(elem_t);
|
||||||
|
let global = ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("global".into())));
|
||||||
|
let acc = ConstAccessor::Attr(ConstAttribute::new(global, Identifier::private("Iterable".into())));
|
||||||
|
TypeSpec::poly(acc, ConstArgs::pos_only(vec![elem_t], None))
|
||||||
|
}
|
||||||
"list" => {
|
"list" => {
|
||||||
let len = ConstExpr::Accessor(ConstAccessor::Local(
|
let len = ConstExpr::Accessor(ConstAccessor::Local(
|
||||||
self.convert_ident("_".into(), args.location),
|
self.convert_ident("_".into(), args.location),
|
||||||
|
|
@ -565,7 +611,9 @@ impl ASTConverter {
|
||||||
};
|
};
|
||||||
let elem_t = ConstPosArg::new(elem_t);
|
let elem_t = ConstPosArg::new(elem_t);
|
||||||
let len = ConstPosArg::new(len);
|
let len = ConstPosArg::new(len);
|
||||||
TypeSpec::poly(Identifier::private("Array!".into()), ConstArgs::new(vec![elem_t, len], None, vec![], None))
|
let global = ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("global".into())));
|
||||||
|
let acc = ConstAccessor::Attr(ConstAttribute::new(global, Identifier::private("Array!".into())));
|
||||||
|
TypeSpec::poly(acc, ConstArgs::new(vec![elem_t, len], None, vec![], None))
|
||||||
}
|
}
|
||||||
"dict" => {
|
"dict" => {
|
||||||
let ExpressionType::Tuple { mut elements } = args.node else {
|
let ExpressionType::Tuple { mut elements } = args.node else {
|
||||||
|
|
@ -591,7 +639,9 @@ impl ASTConverter {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let dict = ConstPosArg::new(ConstExpr::Dict(ConstDict::new(l_brace, r_brace, vec![ConstKeyValue::new(key_t, val_t)])));
|
let dict = ConstPosArg::new(ConstExpr::Dict(ConstDict::new(l_brace, r_brace, vec![ConstKeyValue::new(key_t, val_t)])));
|
||||||
TypeSpec::poly(Identifier::private("Dict!".into()), ConstArgs::new(vec![dict], None, vec![], None))
|
let global = ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("global".into())));
|
||||||
|
let acc = ConstAccessor::Attr(ConstAttribute::new(global, Identifier::private("Dict!".into())));
|
||||||
|
TypeSpec::poly(acc, ConstArgs::new(vec![dict], None, vec![], None))
|
||||||
}
|
}
|
||||||
"tuple" => {
|
"tuple" => {
|
||||||
let ExpressionType::Tuple { elements } = args.node else {
|
let ExpressionType::Tuple { elements } = args.node else {
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ fn exec_warns() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_typespec() {
|
fn exec_typespec() {
|
||||||
expect("tests/typespec.py", 0, 4);
|
expect("tests/typespec.py", 0, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from typing import Union, Optional, Literal
|
from typing import Union, Optional, Literal, Callable
|
||||||
|
from collections.abc import Iterable
|
||||||
|
|
||||||
i: Union[int, str] = 1 # OK
|
i: Union[int, str] = 1 # OK
|
||||||
j: Union[int, str] = "aa" # OK
|
j: Union[int, str] = "aa" # OK
|
||||||
|
|
@ -14,3 +15,12 @@ def f(x: Union[int, str]) -> None:
|
||||||
|
|
||||||
f(1) # OK
|
f(1) # OK
|
||||||
f(None) # ERR
|
f(None) # ERR
|
||||||
|
|
||||||
|
def g(x: int) -> int:
|
||||||
|
return x
|
||||||
|
|
||||||
|
_: Callable[[Union[int, str]], None] = f # OK
|
||||||
|
_: Callable[[Union[int, str]], None] = g # ERR
|
||||||
|
|
||||||
|
_: Iterable[int] = [1] # OK
|
||||||
|
_: Iterable[int] = ["a"] # ERR
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue