feat: support `Callable/Iterable`

This commit is contained in:
Shunsuke Shibayama 2023-05-03 15:14:26 +09:00
parent b8de76f8a9
commit 12cdb09559
6 changed files with 90 additions and 25 deletions

16
Cargo.lock generated
View File

@ -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",

View File

@ -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"] }

View File

@ -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`)
--- ---

View File

@ -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 {

View File

@ -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]

View File

@ -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