This commit is contained in:
Shunsuke Shibayama 2023-02-25 17:18:18 +09:00
parent 5d5b4713dd
commit deb7382dcb
6 changed files with 116 additions and 30 deletions

16
Cargo.lock generated
View File

@ -253,8 +253,7 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]] [[package]]
name = "els" name = "els"
version = "0.1.19-nightly.0" version = "0.1.19-nightly.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/erg-lang/erg?branch=main#0f0d04202014c002fbbafa88ff9d42067d57f201"
checksum = "fc21e1a7815740ad6debfd616bd9f5551dc4b10fa1b4e0e2cec42ddf57dbc7d8"
dependencies = [ dependencies = [
"erg_common", "erg_common",
"erg_compiler", "erg_compiler",
@ -275,8 +274,7 @@ dependencies = [
[[package]] [[package]]
name = "erg_common" name = "erg_common"
version = "0.6.7-nightly.0" version = "0.6.7-nightly.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/erg-lang/erg?branch=main#0f0d04202014c002fbbafa88ff9d42067d57f201"
checksum = "d8d2357638900c5d5f2ee751b4fd2254932fda6a1c50939ffbc8a7acd5903ce9"
dependencies = [ dependencies = [
"backtrace-on-stack-overflow", "backtrace-on-stack-overflow",
"hermit-abi", "hermit-abi",
@ -287,8 +285,7 @@ dependencies = [
[[package]] [[package]]
name = "erg_compiler" name = "erg_compiler"
version = "0.6.7-nightly.0" version = "0.6.7-nightly.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/erg-lang/erg?branch=main#0f0d04202014c002fbbafa88ff9d42067d57f201"
checksum = "682faa374e190771be607591426293f6fb56f22f8ed08c3d424a27615bb261cd"
dependencies = [ dependencies = [
"erg_common", "erg_common",
"erg_parser", "erg_parser",
@ -297,8 +294,7 @@ dependencies = [
[[package]] [[package]]
name = "erg_parser" name = "erg_parser"
version = "0.6.7-nightly.0" version = "0.6.7-nightly.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/erg-lang/erg?branch=main#0f0d04202014c002fbbafa88ff9d42067d57f201"
checksum = "e3e3ee6c10e35b83fe0c6c675ab1697aa72d175e4d10cbcf9a8057485192a604"
dependencies = [ dependencies = [
"erg_common", "erg_common",
"unicode-xid 0.2.4", "unicode-xid 0.2.4",
@ -920,9 +916,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.108" version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d56e159d99e6c2b93995d171050271edb50ecc5288fbc7cc17de8fdce4e58c14" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View File

@ -22,13 +22,13 @@ edition = "2021"
repository = "https://github.com/mtshiba/pylyzer" repository = "https://github.com/mtshiba/pylyzer"
[workspace.dependencies] [workspace.dependencies]
erg_common = { version = "0.6.7-nightly.0", features = ["py_compatible", "els"] } # erg_common = { version = "0.6.7-nightly.0", features = ["py_compatible", "els"] }
erg_compiler = { version = "0.6.7-nightly.0", features = ["py_compatible", "els"] } # erg_compiler = { version = "0.6.7-nightly.0", features = ["py_compatible", "els"] }
els = { version = "0.1.19-nightly.0", features = ["py_compatible"] } # els = { version = "0.1.19-nightly.0", features = ["py_compatible"] }
rustpython-parser = "0.1.2" rustpython-parser = "0.1.2"
# erg_compiler = { git = "https://github.com/erg-lang/erg", branch = "main", features = ["py_compatible", "els"] } 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"] } 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"] } els = { git = "https://github.com/erg-lang/erg", branch = "main", features = ["py_compatible"] }
[features] [features]
debug = ["erg_compiler/debug", "erg_common/debug", "py2erg/debug"] debug = ["erg_compiler/debug", "erg_common/debug", "py2erg/debug"]

View File

@ -90,7 +90,11 @@ pylyzer converts Python ASTs to Erg ASTs and passes them to Erg's type checker.
* [x] local scripts resolving * [x] local scripts resolving
* [ ] local packages resolving * [ ] local packages resolving
* [ ] compound type checking * [ ] compound type checking
* [ ] type assertion * [x] `Union`
* [x] `Optional`
* [x] `list`
* [ ] others
* [ ] type assertion (`typing.cast`)
--- ---

View File

@ -6,12 +6,13 @@ use erg_common::traits::{Locational, Stream};
use erg_common::{log, set}; use erg_common::{log, set};
use erg_compiler::artifact::IncompleteArtifact; use erg_compiler::artifact::IncompleteArtifact;
use erg_compiler::erg_parser::ast::{ use erg_compiler::erg_parser::ast::{
Accessor, Args, Array, BinOp, Block, ClassAttr, ClassAttrs, ClassDef, ConstArgs, Decorator, Accessor, Args, Array, ArrayTypeSpec, BinOp, Block, ClassAttr, ClassAttrs, ClassDef,
Def, DefBody, DefId, DefaultParamSignature, Dict, Dummy, Expr, Identifier, KeyValue, Lambda, ConstAccessor, ConstArgs, ConstExpr, Decorator, Def, DefBody, DefId, DefaultParamSignature,
LambdaSignature, Literal, Methods, Module, NonDefaultParamSignature, NormalArray, NormalDict, Dict, Dummy, Expr, Identifier, KeyValue, Lambda, LambdaSignature, Literal, Methods, Module,
NormalRecord, NormalSet, NormalTuple, ParamPattern, Params, PosArg, PreDeclTypeSpec, ReDef, NonDefaultParamSignature, NormalArray, NormalDict, NormalRecord, NormalSet, NormalTuple,
Record, RecordAttrs, Set, Signature, SimpleTypeSpec, SubrSignature, Tuple, TypeAscription, ParamPattern, Params, PosArg, PreDeclTypeSpec, ReDef, Record, RecordAttrs, Set, Signature,
TypeBoundSpecs, TypeSpec, TypeSpecWithOp, UnaryOp, VarName, VarPattern, VarSignature, SimpleTypeSpec, SubrSignature, Tuple, TypeAscription, TypeBoundSpecs, TypeSpec, TypeSpecWithOp,
UnaryOp, VarName, VarPattern, VarSignature,
}; };
use erg_compiler::erg_parser::token::{Token, TokenKind, COLON, DOT, EQUAL}; use erg_compiler::erg_parser::token::{Token, TokenKind, COLON, DOT, EQUAL};
use erg_compiler::error::CompileErrors; use erg_compiler::error::CompileErrors;
@ -502,17 +503,89 @@ impl ASTConverter {
Lambda::new(sig, op, Block::new(body), DefId(0)) Lambda::new(sig, op, Block::new(body), DefId(0))
} }
fn convert_ident_type_spec(&mut self, name: String, loc: PyLocation) -> SimpleTypeSpec {
SimpleTypeSpec::new(self.convert_ident(name, loc), ConstArgs::empty())
}
fn gen_dummy_type_spec(loc: PyLocation) -> TypeSpec {
TypeSpec::Infer(Token::new(
TokenKind::UBar,
"_",
loc.row() as u32,
loc.column() as u32 - 1,
))
}
// TODO:
fn convert_compound_type_spec(
&mut self,
name: String,
args: Located<ExpressionType>,
) -> TypeSpec {
match &name[..] {
"Union" => {
let ExpressionType::Tuple { mut elements } = args.node else {
return Self::gen_dummy_type_spec(args.location);
};
let lhs = self.convert_type_spec(elements.remove(0));
let rhs = self.convert_type_spec(elements.remove(0));
TypeSpec::or(lhs, rhs)
}
"Optional" => {
let loc = args.location;
let t = self.convert_type_spec(args);
let ident = Identifier::private_with_line("NoneType".into(), loc.row() as u32);
let none = TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(SimpleTypeSpec::new(
ident,
ConstArgs::empty(),
)));
TypeSpec::or(t, none)
}
"list" => {
let len = ConstExpr::Accessor(ConstAccessor::Local(
self.convert_ident("_".into(), args.location),
));
let elem_t = self.convert_type_spec(args);
TypeSpec::Array(ArrayTypeSpec::new(elem_t, len))
}
_ => Self::gen_dummy_type_spec(args.location),
}
}
fn convert_type_spec(&mut self, expr: Located<ExpressionType>) -> TypeSpec { fn convert_type_spec(&mut self, expr: Located<ExpressionType>) -> TypeSpec {
#[allow(clippy::collapsible_match)]
match expr.node { match expr.node {
ExpressionType::Identifier { name } => TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple( ExpressionType::Identifier { name } => TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(
SimpleTypeSpec::new(self.convert_ident(name, expr.location), ConstArgs::empty()), self.convert_ident_type_spec(name, expr.location),
)),
_other => TypeSpec::Infer(Token::new(
TokenKind::UBar,
"_",
expr.location.row() as u32,
expr.location.column() as u32 - 1,
)), )),
ExpressionType::Attribute { value, name } => {
let namespace = Box::new(self.convert_expr(*value));
let t = self.convert_ident_type_spec(name, expr.location);
let predecl = PreDeclTypeSpec::Attr { namespace, t };
TypeSpec::PreDeclTy(predecl)
}
ExpressionType::Subscript { a, b } => match a.node {
ExpressionType::Identifier { name } => self.convert_compound_type_spec(name, *b),
other => {
log!(err "unknown: {other:?}");
Self::gen_dummy_type_spec(a.location)
}
},
ExpressionType::Binop { a, op, b } => {
match op {
// A | B
Operator::BitOr => {
let lhs = self.convert_type_spec(*a);
let rhs = self.convert_type_spec(*b);
TypeSpec::or(lhs, rhs)
}
_ => Self::gen_dummy_type_spec(expr.location),
}
}
other => {
log!(err "unknown: {other:?}");
Self::gen_dummy_type_spec(expr.location)
}
} }
} }

View File

@ -70,3 +70,8 @@ fn exec_errors() {
fn exec_warns() { fn exec_warns() {
expect("tests/warns.py", 2, 0); expect("tests/warns.py", 2, 0);
} }
#[test]
fn exec_typespec() {
expect("tests/typespec.py", 0, 2);
}

8
tests/typespec.py Normal file
View File

@ -0,0 +1,8 @@
from typing import Union, Optional
i: Union[int, str] = 1 # OK
j: Union[int, str] = "aa" # OK
k: Union[list[int], str] = 1 # ERR
l: Union[list[int], str] = [1] # OK
o: Optional[int] = None # OK
p: Optional[int] = "a" # ERR