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]]
|
||||
name = "els"
|
||||
version = "0.1.24-nightly.4"
|
||||
version = "0.1.24-nightly.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f74cdce8d05df8b4a6090cc892e34a30ab6880f5ed8786e9346fe4d4fb4c47d5"
|
||||
checksum = "3db3f0318812d7401d51a3232f256faaa15963f30f4bf7bc07dc8bc73b849353"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"erg_compiler",
|
||||
|
|
@ -274,9 +274,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
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"
|
||||
checksum = "07cc57d02fe5520b0f0a42d30be2604edafa71a35074a35f579f2ca91533d965"
|
||||
checksum = "8c34723b8e8f53e11205330924f36425d52b2ebae66a5d45e889fb83a01be4fb"
|
||||
dependencies = [
|
||||
"backtrace-on-stack-overflow",
|
||||
"hermit-abi",
|
||||
|
|
@ -286,9 +286,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
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"
|
||||
checksum = "101a854704b5bda829d4fa6005d590b2f426ce6624b8361118b4949c7d90c859"
|
||||
checksum = "beef1255c0fe34d84892d6b3eecd4506a77ba71d24a8b143795f1c5b2e4f6877"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"erg_parser",
|
||||
|
|
@ -296,9 +296,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
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"
|
||||
checksum = "43fe0229517462ba79374a8eb1b16a183f0854744af6d4ebfcd4b2ff05539121"
|
||||
checksum = "a16c93aca8cc69dd920dd3a6fb0c6ab9054bdfe3e46ada0ea89dce8896617296"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"unicode-xid 0.2.4",
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@ edition = "2021"
|
|||
repository = "https://github.com/mtshiba/pylyzer"
|
||||
|
||||
[workspace.dependencies]
|
||||
erg_common = { version = "0.6.12-nightly.4", features = ["py_compat", "els"] }
|
||||
erg_compiler = { version = "0.6.12-nightly.4", features = ["py_compat", "els"] }
|
||||
els = { version = "0.1.24-nightly.4", features = ["py_compat"] }
|
||||
erg_common = { version = "0.6.12-nightly.6", features = ["py_compat", "els"] }
|
||||
erg_compiler = { version = "0.6.12-nightly.6", features = ["py_compat", "els"] }
|
||||
els = { version = "0.1.24-nightly.6", features = ["py_compat"] }
|
||||
rustpython-parser = "0.1.2"
|
||||
# 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"] }
|
||||
|
|
|
|||
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] local scripts resolving
|
||||
* [ ] local packages resolving
|
||||
* [ ] compound type checking
|
||||
* [x] `Union`
|
||||
* [x] `Optional`
|
||||
* [x] collection types
|
||||
* [x] `list`
|
||||
* [x] `dict`
|
||||
* [x] `tuple`
|
||||
* [ ] `typing`
|
||||
* [x] `Union`
|
||||
* [x] `Optional`
|
||||
* [x] `Literal`
|
||||
* [x] `Callable`
|
||||
* [ ] `TypedDict`
|
||||
* [ ] type variable (`TypeVar`, `Generic`)
|
||||
* [ ] `Protocol`
|
||||
* [ ] `Final`
|
||||
* [ ] `Annotated`
|
||||
* [ ] `TypeAlias`
|
||||
* [ ] type guard (`TypeGuard`)
|
||||
* [ ] others
|
||||
* `collections.abc`
|
||||
* [x] `Iterable`
|
||||
* [ ] others
|
||||
* [ ] type variable (`TypeVar`, `Generic`)
|
||||
* [ ] `Protocol`
|
||||
* [ ] `Final`
|
||||
* [ ] `Annotated`
|
||||
* [ ] `TypeAlias`
|
||||
* [x] type assertion (`typing.cast`)
|
||||
* [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,
|
||||
Signature, SubrSignature, Tuple, TypeAscription, TypeBoundSpecs, TypeSpec,
|
||||
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::token::{Token, TokenKind, AS, DOT, EQUAL};
|
||||
|
|
@ -29,6 +29,8 @@ use crate::ast_util::length;
|
|||
use crate::clone::clone_loc_expr;
|
||||
use crate::error::*;
|
||||
|
||||
pub const ARROW: Token = Token::dummy(TokenKind::FuncArrow, "->");
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum NameKind {
|
||||
Variable,
|
||||
|
|
@ -550,6 +552,50 @@ impl ASTConverter {
|
|||
let elems = ConstArgs::new(elems, None, vec![], None);
|
||||
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" => {
|
||||
let len = ConstExpr::Accessor(ConstAccessor::Local(
|
||||
self.convert_ident("_".into(), args.location),
|
||||
|
|
@ -565,7 +611,9 @@ impl ASTConverter {
|
|||
};
|
||||
let elem_t = ConstPosArg::new(elem_t);
|
||||
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" => {
|
||||
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)])));
|
||||
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" => {
|
||||
let ExpressionType::Tuple { elements } = args.node else {
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ fn exec_warns() {
|
|||
|
||||
#[test]
|
||||
fn exec_typespec() {
|
||||
expect("tests/typespec.py", 0, 4);
|
||||
expect("tests/typespec.py", 0, 6);
|
||||
}
|
||||
|
||||
#[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
|
||||
j: Union[int, str] = "aa" # OK
|
||||
|
|
@ -14,3 +15,12 @@ def f(x: Union[int, str]) -> None:
|
|||
|
||||
f(1) # OK
|
||||
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