From fe8b15291f4461cb130ac49ed599e3d812f6b55d Mon Sep 17 00:00:00 2001 From: Chris Krycho Date: Mon, 26 Aug 2024 13:08:18 -0600 Subject: [PATCH] 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. --- .../src/types/infer.rs | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs index c5f5d74361a26..0631232809419 100644 --- a/crates/red_knot_python_semantic/src/types/infer.rs +++ b/crates/red_knot_python_semantic/src/types/infer.rs @@ -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();