mirror of https://github.com/mtshiba/pylyzer
fix: TypeVar bug
This commit is contained in:
parent
6e88efebe8
commit
94221a6419
|
|
@ -139,9 +139,9 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
|||
|
||||
[[package]]
|
||||
name = "els"
|
||||
version = "0.1.54-nightly.3"
|
||||
version = "0.1.54-nightly.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfe2679dec933507f4d9abfa4e6468d3b312790e933b3269ce2a2a2bc910bd3d"
|
||||
checksum = "bdc6282121d9e2871553e0731cfb88119cbfe76ce8aab08ac2be01f5644e3bee"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"erg_compiler",
|
||||
|
|
@ -153,9 +153,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "erg_common"
|
||||
version = "0.6.42-nightly.3"
|
||||
version = "0.6.42-nightly.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c5582717e4cd56c2015263641441c7f3c19ae030bd804565f0b93ad0a8c536e"
|
||||
checksum = "c0dfc622cc65f230a05a284a21f62c8f4a3c964c51c97881cc4e01202ef2a3c0"
|
||||
dependencies = [
|
||||
"backtrace-on-stack-overflow",
|
||||
"erg_proc_macros",
|
||||
|
|
@ -165,9 +165,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "erg_compiler"
|
||||
version = "0.6.42-nightly.3"
|
||||
version = "0.6.42-nightly.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "299406202ab6dfe28be95c3d6ceae19d9821624ef666a978b42112f658b528c4"
|
||||
checksum = "42247c4ab1eb33ed3e2e9e74f4773565eba4491f76bfbda4b965015938704ca1"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"erg_parser",
|
||||
|
|
@ -175,9 +175,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "erg_parser"
|
||||
version = "0.6.42-nightly.3"
|
||||
version = "0.6.42-nightly.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc13d9b7c3342e1a4ccd4159e39c99769a30733ac6cf44c22593d0aecb169af9"
|
||||
checksum = "6c921c178517c2071e45418e8c5b35e0c3a19021e4459283fd8f6997b89ba216"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"erg_proc_macros",
|
||||
|
|
@ -186,9 +186,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "erg_proc_macros"
|
||||
version = "0.6.42-nightly.3"
|
||||
version = "0.6.42-nightly.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8506a5228f462df55923b4a6ca8617ce90a84b52a4b603cedf3dda6beb3243f"
|
||||
checksum = "c1381ca7a7a0781834cb1d617cd8361cca23f880cb9c515d249905d585832734"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@ edition = "2021"
|
|||
repository = "https://github.com/mtshiba/pylyzer"
|
||||
|
||||
[workspace.dependencies]
|
||||
erg_common = { version = "0.6.42-nightly.3", features = ["py_compat", "els"] }
|
||||
erg_compiler = { version = "0.6.42-nightly.3", features = ["py_compat", "els"] }
|
||||
els = { version = "0.1.54-nightly.3", features = ["py_compat"] }
|
||||
erg_common = { version = "0.6.42-nightly.5", features = ["py_compat", "els"] }
|
||||
erg_compiler = { version = "0.6.42-nightly.5", features = ["py_compat", "els"] }
|
||||
els = { version = "0.1.54-nightly.5", features = ["py_compat"] }
|
||||
# rustpython-parser = { version = "0.3.0", features = ["all-nodes-with-ranges", "location"] }
|
||||
# rustpython-ast = { version = "0.3.0", features = ["all-nodes-with-ranges", "location"] }
|
||||
rustpython-parser = { git = "https://github.com/RustPython/Parser", version = "0.4.0", features = ["all-nodes-with-ranges", "location"] }
|
||||
|
|
|
|||
|
|
@ -221,6 +221,7 @@ pub enum ShadowingMode {
|
|||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct TypeVarInfo {
|
||||
name: String,
|
||||
constraints: Vec<Expr>,
|
||||
bound: Option<Expr>,
|
||||
}
|
||||
|
||||
|
|
@ -235,8 +236,12 @@ impl fmt::Display for TypeVarInfo {
|
|||
}
|
||||
|
||||
impl TypeVarInfo {
|
||||
pub const fn new(name: String, bound: Option<Expr>) -> Self {
|
||||
Self { name, bound }
|
||||
pub const fn new(name: String, constraints: Vec<Expr>, bound: Option<Expr>) -> Self {
|
||||
Self {
|
||||
name,
|
||||
constraints,
|
||||
bound,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1662,6 +1667,7 @@ impl ASTConverter {
|
|||
|
||||
fn get_type_bounds(&mut self, type_params: Vec<TypeParam>) -> TypeBoundSpecs {
|
||||
let mut bounds = TypeBoundSpecs::empty();
|
||||
let mut errs = vec![];
|
||||
if type_params.is_empty() {
|
||||
for ty in self.cur_appeared_type_names() {
|
||||
let name = VarName::from_str(ty.clone().into());
|
||||
|
|
@ -1672,6 +1678,42 @@ impl ASTConverter {
|
|||
.unwrap_or(TypeSpec::Infer(name.token().clone()));
|
||||
let spec = TypeSpecWithOp::new(op, t_spec, bound.clone());
|
||||
TypeBoundSpec::non_default(name, spec)
|
||||
} else if !tv_info.constraints.is_empty() {
|
||||
if tv_info.constraints.len() == 1 {
|
||||
let err = CompileError::syntax_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
pyloc_to_ergloc(type_params[0].range()),
|
||||
self.cur_namespace(),
|
||||
"TypeVar must have at least two constrained types".into(),
|
||||
None,
|
||||
);
|
||||
errs.push(err);
|
||||
}
|
||||
let op = Token::dummy(TokenKind::Colon, ":");
|
||||
let mut elems = vec![];
|
||||
for constraint in tv_info.constraints.iter() {
|
||||
if let Ok(expr) = Parser::validate_const_expr(constraint.clone()) {
|
||||
elems.push(ConstPosArg::new(expr));
|
||||
}
|
||||
}
|
||||
let t_spec = TypeSpec::Enum(ConstArgs::pos_only(elems, None));
|
||||
let elems = Args::pos_only(
|
||||
tv_info
|
||||
.constraints
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(PosArg::new)
|
||||
.collect(),
|
||||
None,
|
||||
);
|
||||
let expr = Expr::Set(Set::Normal(NormalSet::new(
|
||||
Token::DUMMY,
|
||||
Token::DUMMY,
|
||||
elems,
|
||||
)));
|
||||
let spec = TypeSpecWithOp::new(op, t_spec, expr);
|
||||
TypeBoundSpec::non_default(name, spec)
|
||||
} else {
|
||||
TypeBoundSpec::Omitted(name)
|
||||
};
|
||||
|
|
@ -1696,6 +1738,7 @@ impl ASTConverter {
|
|||
};
|
||||
bounds.push(spec);
|
||||
}
|
||||
self.errs.extend(errs);
|
||||
bounds
|
||||
}
|
||||
|
||||
|
|
@ -1893,8 +1936,14 @@ impl ASTConverter {
|
|||
} else {
|
||||
name.id.to_string()
|
||||
};
|
||||
let bound = call.args.nth_or_key(1, "bound").cloned();
|
||||
let info = TypeVarInfo::new(arg, bound);
|
||||
let mut constraints = vec![];
|
||||
let mut nth = 1;
|
||||
while let Some(constr) = call.args.get_nth(nth) {
|
||||
constraints.push(constr.clone());
|
||||
nth += 1;
|
||||
}
|
||||
let bound = call.args.get_with_key("bound").cloned();
|
||||
let info = TypeVarInfo::new(arg, constraints, bound);
|
||||
self.define_type_var(name.id.to_string(), info);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,3 +71,10 @@ class F:
|
|||
_ = F(1)
|
||||
_ = F(1, 2)
|
||||
_ = F(1, z=1, y=2)
|
||||
|
||||
class G(DoesNotExist): # ERR
|
||||
def foo(self):
|
||||
return 1
|
||||
|
||||
g = G()
|
||||
assert g.foo() == 1
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ fn exec_func() -> Result<(), String> {
|
|||
|
||||
#[test]
|
||||
fn exec_class() -> Result<(), String> {
|
||||
expect("tests/class.py", 0, 5)
|
||||
expect("tests/class.py", 0, 6)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -139,7 +139,7 @@ fn exec_shadowing() -> Result<(), String> {
|
|||
|
||||
#[test]
|
||||
fn exec_typevar() -> Result<(), String> {
|
||||
expect("tests/typevar.py", 0, 2)
|
||||
expect("tests/typevar.py", 0, 3)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -1,17 +1,24 @@
|
|||
from typing import TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
U = TypeVar("U", int)
|
||||
U = TypeVar("U", bound=int)
|
||||
IS = TypeVar("IS", int, str)
|
||||
def id(x: T) -> T:
|
||||
return x
|
||||
|
||||
def id_int(x: U) -> U:
|
||||
return x
|
||||
|
||||
def id_int_or_str(x: IS) -> IS:
|
||||
return x
|
||||
|
||||
_ = id(1) + 1 # OK
|
||||
_ = id("a") + "b" # OK
|
||||
_ = id_int(1) # OK
|
||||
_ = id_int("a") # ERR
|
||||
_ = id_int_or_str(1) # OK
|
||||
_ = id_int_or_str("a") # OK
|
||||
_ = id_int_or_str(None) # ERR
|
||||
|
||||
def id2[T](x: T) -> T:
|
||||
return x
|
||||
|
|
|
|||
Loading…
Reference in New Issue