Fix PLW1508 false positive for default string created via a mult operation (#14841)

This commit is contained in:
Thibaut Decombe 2024-12-08 19:25:47 +01:00 committed by GitHub
parent 85402097fc
commit 8d9e408dbb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 44 additions and 3 deletions

View file

@ -13,3 +13,5 @@ os.getenv("B", Z)
os.getenv("AA", "GOOD" if Z else "BAR")
os.getenv("AA", 1 if Z else "BAR") # [invalid-envvar-default]
os.environ.get("TEST", 12) # [invalid-envvar-default]
os.environ.get("TEST", "AA" * 12)
os.environ.get("TEST", 13 * "AA")

View file

@ -49,4 +49,5 @@ invalid_envvar_default.py:14:17: PLW1508 Invalid type for environment variable d
14 | os.getenv("AA", 1 if Z else "BAR") # [invalid-envvar-default]
| ^^^^^^^^^^^^^^^^^ PLW1508
15 | os.environ.get("TEST", 12) # [invalid-envvar-default]
16 | os.environ.get("TEST", "AA" * 12)
|

View file

@ -49,6 +49,7 @@ invalid_envvar_default.py:14:17: PLW1508 Invalid type for environment variable d
14 | os.getenv("AA", 1 if Z else "BAR") # [invalid-envvar-default]
| ^^^^^^^^^^^^^^^^^ PLW1508
15 | os.environ.get("TEST", 12) # [invalid-envvar-default]
16 | os.environ.get("TEST", "AA" * 12)
|
invalid_envvar_default.py:15:24: PLW1508 Invalid type for environment variable default; expected `str` or `None`
@ -57,4 +58,6 @@ invalid_envvar_default.py:15:24: PLW1508 Invalid type for environment variable d
14 | os.getenv("AA", 1 if Z else "BAR") # [invalid-envvar-default]
15 | os.environ.get("TEST", 12) # [invalid-envvar-default]
| ^^ PLW1508
16 | os.environ.get("TEST", "AA" * 12)
17 | os.environ.get("TEST", 13 * "AA")
|

View file

@ -234,12 +234,39 @@ impl From<&Expr> for ResolvedPythonType {
}
_ => {}
},
// Standard arithmetic operators, which coerce to the "highest" number type.
Operator::Mult | Operator::FloorDiv | Operator::Pow => match (
Operator::Mult => match (
ResolvedPythonType::from(left.as_ref()),
ResolvedPythonType::from(right.as_ref()),
) {
// Ex) `1 - 2`
// Ex) `2 * 4`
(
ResolvedPythonType::Atom(PythonType::Number(left)),
ResolvedPythonType::Atom(PythonType::Number(right)),
) => {
return ResolvedPythonType::Atom(PythonType::Number(
left.coerce(right),
));
}
// Ex) `"1" * 2` or `2 * "1"`
(
ResolvedPythonType::Atom(PythonType::String),
ResolvedPythonType::Atom(PythonType::Number(NumberLike::Integer)),
)
| (
ResolvedPythonType::Atom(PythonType::Number(NumberLike::Integer)),
ResolvedPythonType::Atom(PythonType::String),
) => return ResolvedPythonType::Atom(PythonType::String),
(ResolvedPythonType::Atom(_), ResolvedPythonType::Atom(_)) => {
return ResolvedPythonType::TypeError;
}
_ => {}
},
// Standard arithmetic operators, which coerce to the "highest" number type.
Operator::FloorDiv | Operator::Pow => match (
ResolvedPythonType::from(left.as_ref()),
ResolvedPythonType::from(right.as_ref()),
) {
// Ex) `2 ** 4`
(
ResolvedPythonType::Atom(PythonType::Number(left)),
ResolvedPythonType::Atom(PythonType::Number(right)),
@ -476,6 +503,14 @@ mod tests {
ResolvedPythonType::from(parse("1.0 * 2j").expr()),
ResolvedPythonType::Atom(PythonType::Number(NumberLike::Complex))
);
assert_eq!(
ResolvedPythonType::from(parse("'AA' * 2").expr()),
ResolvedPythonType::Atom(PythonType::String)
);
assert_eq!(
ResolvedPythonType::from(parse("4 * 'AA'").expr()),
ResolvedPythonType::Atom(PythonType::String)
);
assert_eq!(
ResolvedPythonType::from(parse("1 / True").expr()),
ResolvedPythonType::Atom(PythonType::Number(NumberLike::Float))