red-knot: implement unary minus on integer literals (#13114)

# Summary

Add support for the first unary operator: negating integer literals. The
resulting type is another integer literal, with the value being the
negated value of the literal. All other types continue to return
`Type::Unknown` for the present, but this is designed to make it easy to
extend easily with other combinations of operator and operand.

Contributes to #12701.

## Test Plan

Add tests with basic negation, including of very large integers and
double negation.
This commit is contained in:
Chris Krycho 2024-08-26 13:08:18 -06:00 committed by GitHub
parent c8e01d7c53
commit fe8b15291f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -28,7 +28,7 @@ use salsa::plumbing::AsId;
use ruff_db::files::File;
use ruff_db::parsed::parsed_module;
use ruff_python_ast as ast;
use ruff_python_ast::{self as ast, UnaryOp};
use ruff_python_ast::{AnyNodeRef, ExprContext};
use ruff_text_size::Ranged;
@ -1708,14 +1708,14 @@ impl<'db> TypeInferenceBuilder<'db> {
fn infer_unary_expression(&mut self, unary: &ast::ExprUnaryOp) -> Type<'db> {
let ast::ExprUnaryOp {
range: _,
op: _,
op,
operand,
} = unary;
self.infer_expression(operand);
// TODO unary op types
Type::Unknown
match (op, self.infer_expression(operand)) {
(UnaryOp::USub, Type::IntLiteral(value)) => Type::IntLiteral(-value),
_ => Type::Unknown, // TODO other unary op types
}
}
fn infer_binary_expression(&mut self, binary: &ast::ExprBinOp) -> Type<'db> {
@ -2296,6 +2296,26 @@ mod tests {
Ok(())
}
#[test]
fn negated_int_literal() -> anyhow::Result<()> {
let mut db = setup_db();
db.write_dedented(
"src/a.py",
"
x = -1
y = -1234567890987654321
z = --987
",
)?;
assert_public_ty(&db, "src/a.py", "x", "Literal[-1]");
assert_public_ty(&db, "src/a.py", "y", "Literal[-1234567890987654321]");
assert_public_ty(&db, "src/a.py", "z", "Literal[987]");
Ok(())
}
#[test]
fn boolean_literal() -> anyhow::Result<()> {
let mut db = setup_db();