Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

red-knot: Implement the not operator for all Type variants #13432

Merged
merged 2 commits into from
Sep 25, 2024

Conversation

haarisr
Copy link
Contributor

@haarisr haarisr commented Sep 21, 2024

Summary

Adds unary not operator (not) for integer literals.

Not sure if this is the best way to do it. Feedback would be helpful

Contributes to #12701

Test Plan

Added new test basing of the test values in the unary sub operator. Small and large value for both positive and negative integers as well as for zero (which is the only True) test case

Copy link
Contributor

github-actions bot commented Sep 21, 2024

ruff-ecosystem results

Linter (stable)

ℹ️ ecosystem check detected linter changes. (+49 -0 violations, +4 -0 fixes in 7 projects; 47 projects unchanged)

apache/airflow (+4 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --no-preview --select ALL

+ airflow/providers/amazon/aws/secrets/secrets_manager.py:173:29: SIM910 [*] Use `kwargs.get("profile_name")` instead of `kwargs.get("profile_name", None)`
+ airflow/providers/amazon/aws/secrets/systems_manager.py:107:29: SIM910 [*] Use `kwargs.get("profile_name")` instead of `kwargs.get("profile_name", None)`
+ tests/conftest.py:954:28: SIM910 [*] Use `kwargs.get("default_args")` instead of `kwargs.get("default_args", None)`
+ tests/providers/elasticsearch/log/elasticmock/utilities/__init__.py:88:32: SIM910 [*] Use `kwargs.get("body")` instead of `kwargs.get("body", None)`

apache/superset (+0 -0 violations, +2 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --no-preview --select ALL

- superset/db_engine_specs/presto.py:650:13: SIM118 Use `key in dict` instead of `key in dict.keys()`
+ superset/db_engine_specs/presto.py:650:13: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`

bokeh/bokeh (+2 -0 violations, +2 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --no-preview --select ALL

- src/bokeh/plotting/_figure.py:193:13: SIM118 Use `key in dict` instead of `key in dict.keys()`
+ src/bokeh/plotting/_figure.py:193:13: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
+ src/bokeh/plotting/contour.py:205:17: SIM910 [*] Use `visuals.get("line_color")` instead of `visuals.get("line_color", None)`
+ src/bokeh/plotting/contour.py:222:17: SIM910 [*] Use `visuals.get("fill_color")` instead of `visuals.get("fill_color", None)`

milvus-io/pymilvus (+37 -0 violations, +0 -0 fixes)

+ pymilvus/bulk_writer/local_bulk_writer.py:113:21: SIM910 [*] Use `kwargs.get("call_back")` instead of `kwargs.get("call_back", None)`
+ pymilvus/client/asynch.py:108:18: SIM910 [*] Use `kwargs.get("timeout")` instead of `kwargs.get("timeout", None)`
+ pymilvus/client/grpc_handler.py:1255:23: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/grpc_handler.py:128:13: SIM910 [*] Use `kwargs.get("user")` instead of `kwargs.get("user", None)`
+ pymilvus/client/grpc_handler.py:129:13: SIM910 [*] Use `kwargs.get("password")` instead of `kwargs.get("password", None)`
+ pymilvus/client/grpc_handler.py:130:13: SIM910 [*] Use `kwargs.get("token")` instead of `kwargs.get("token", None)`
+ pymilvus/client/grpc_handler.py:1464:23: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/grpc_handler.py:1991:23: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/grpc_handler.py:473:18: SIM910 [*] Use `kwargs.get("schema")` instead of `kwargs.get("schema", None)`
+ pymilvus/client/grpc_handler.py:570:22: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/grpc_handler.py:602:28: SIM910 [*] Use `kwargs.get("param_name")` instead of `kwargs.get("param_name", None)`
+ pymilvus/client/grpc_handler.py:607:22: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/grpc_handler.py:667:22: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/grpc_handler.py:730:24: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/grpc_handler.py:749:24: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/grpc_handler.py:784:33: SIM910 [*] Use `kwargs.get("guarantee_timestamp")` instead of `kwargs.get("guarantee_timestamp", None)`
+ pymilvus/client/grpc_handler.py:820:33: SIM910 [*] Use `kwargs.get("guarantee_timestamp")` instead of `kwargs.get("guarantee_timestamp", None)`
+ pymilvus/client/grpc_handler.py:90:22: SIM910 [*] Use `kwargs.get("user")` instead of `kwargs.get("user", None)`
+ pymilvus/client/grpc_handler.py:92:36: SIM910 [*] Use `kwargs.get("db_name")` instead of `kwargs.get("db_name", None)`
+ pymilvus/client/grpc_handler.py:980:23: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/prepare.py:1052:17: SIM910 [*] Use `kwargs.get("limit")` instead of `kwargs.get("limit", None)`
+ pymilvus/client/prepare.py:1056:18: SIM910 [*] Use `kwargs.get("offset")` instead of `kwargs.get("offset", None)`
+ pymilvus/client/prepare.py:1135:25: SIM910 [*] Use `kwargs.get("channel_names")` instead of `kwargs.get("channel_names", None)`
+ pymilvus/client/prepare.py:813:12: SIM910 [*] Use `kwargs.get(RANK_GROUP_SCORER)` instead of `kwargs.get(RANK_GROUP_SCORER, None)`
+ pymilvus/client/prepare.py:822:12: SIM910 [*] Use `kwargs.get(GROUP_BY_FIELD)` instead of `kwargs.get(GROUP_BY_FIELD, None)`
+ pymilvus/client/prepare.py:831:12: SIM910 [*] Use `kwargs.get(GROUP_SIZE)` instead of `kwargs.get(GROUP_SIZE, None)`
+ pymilvus/client/prepare.py:840:12: SIM910 [*] Use `kwargs.get(GROUP_STRICT_SIZE)` instead of `kwargs.get(GROUP_STRICT_SIZE, None)`
+ pymilvus/client/prepare.py:92:26: SIM910 [*] Use `kwargs.get("num_partitions")` instead of `kwargs.get("num_partitions", None)`
+ pymilvus/decorators.py:170:21: SIM910 [*] Use `kwargs.get("log_level")` instead of `kwargs.get("log_level", None)`
+ pymilvus/decorators.py:171:22: SIM910 [*] Use `kwargs.get("client_request_id")` instead of `kwargs.get("client_request_id", None)`
+ pymilvus/decorators.py:56:24: SIM910 [*] Use `kwargs.get("timeout")` instead of `kwargs.get("timeout", None)`
+ pymilvus/decorators.py:57:28: SIM910 [*] Use `kwargs.get("retry_times")` instead of `kwargs.get("retry_times", None)`
+ pymilvus/orm/collection.py:188:51: SIM910 [*] Use `kwargs.get("auto_id")` instead of `kwargs.get("auto_id", None)`
+ pymilvus/orm/schema.py:324:30: SIM910 [*] Use `kwargs.get("default_value")` instead of `kwargs.get("default_value", None)`
... 3 additional changes omitted for project

mlflow/mlflow (+2 -0 violations, +0 -0 fixes)

+ mlflow/openai/_openai_autolog.py:203:25: SIM910 [*] Use `kwargs.get("model")` instead of `kwargs.get("model", None)`
+ mlflow/pytorch/_pytorch_autolog.py:52:53: SIM910 [*] Use `kwargs.get("global_step")` instead of `kwargs.get("global_step", None)`

reflex-dev/reflex (+2 -0 violations, +0 -0 fixes)

+ reflex/components/datadisplay/dataeditor.py:332:16: SIM910 [*] Use `props.get("rows")` instead of `props.get("rows", None)`
+ reflex/vars/base.py:242:24: SIM910 [*] Use `kwargs.get("_js_expr")` instead of `kwargs.get("_js_expr", None)`

zulip/zulip (+2 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --no-preview --select ALL

+ corporate/tests/test_stripe.py:652:41: SIM910 [*] Use `kwargs.get("remote_server_plan_start_date")` instead of `kwargs.get("remote_server_plan_start_date", None)`
+ zerver/lib/test_classes.py:1897:37: SIM910 [*] Use `kwargs.get("mentioned_user_group_id")` instead of `kwargs.get("mentioned_user_group_id", None)`

Changes by rule (2 rules affected)

code total + violation - violation + fix - fix
SIM910 49 49 0 0 0
SIM118 4 0 0 4 0

Linter (preview)

ℹ️ ecosystem check detected linter changes. (+49 -0 violations, +4 -0 fixes in 7 projects; 47 projects unchanged)

apache/airflow (+4 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview --select ALL

+ airflow/providers/amazon/aws/secrets/secrets_manager.py:173:29: SIM910 [*] Use `kwargs.get("profile_name")` instead of `kwargs.get("profile_name", None)`
+ airflow/providers/amazon/aws/secrets/systems_manager.py:107:29: SIM910 [*] Use `kwargs.get("profile_name")` instead of `kwargs.get("profile_name", None)`
+ tests/conftest.py:954:28: SIM910 [*] Use `kwargs.get("default_args")` instead of `kwargs.get("default_args", None)`
+ tests/providers/elasticsearch/log/elasticmock/utilities/__init__.py:88:32: SIM910 [*] Use `kwargs.get("body")` instead of `kwargs.get("body", None)`

apache/superset (+0 -0 violations, +2 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview --select ALL

- superset/db_engine_specs/presto.py:650:13: SIM118 Use `key in dict` instead of `key in dict.keys()`
+ superset/db_engine_specs/presto.py:650:13: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`

bokeh/bokeh (+2 -0 violations, +2 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview --select ALL

- src/bokeh/plotting/_figure.py:193:13: SIM118 Use `key in dict` instead of `key in dict.keys()`
+ src/bokeh/plotting/_figure.py:193:13: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
+ src/bokeh/plotting/contour.py:205:17: SIM910 [*] Use `visuals.get("line_color")` instead of `visuals.get("line_color", None)`
+ src/bokeh/plotting/contour.py:222:17: SIM910 [*] Use `visuals.get("fill_color")` instead of `visuals.get("fill_color", None)`

milvus-io/pymilvus (+37 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

+ pymilvus/bulk_writer/local_bulk_writer.py:113:21: SIM910 [*] Use `kwargs.get("call_back")` instead of `kwargs.get("call_back", None)`
+ pymilvus/client/asynch.py:108:18: SIM910 [*] Use `kwargs.get("timeout")` instead of `kwargs.get("timeout", None)`
+ pymilvus/client/grpc_handler.py:1255:23: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/grpc_handler.py:128:13: SIM910 [*] Use `kwargs.get("user")` instead of `kwargs.get("user", None)`
+ pymilvus/client/grpc_handler.py:129:13: SIM910 [*] Use `kwargs.get("password")` instead of `kwargs.get("password", None)`
+ pymilvus/client/grpc_handler.py:130:13: SIM910 [*] Use `kwargs.get("token")` instead of `kwargs.get("token", None)`
+ pymilvus/client/grpc_handler.py:1464:23: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/grpc_handler.py:1991:23: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/grpc_handler.py:473:18: SIM910 [*] Use `kwargs.get("schema")` instead of `kwargs.get("schema", None)`
+ pymilvus/client/grpc_handler.py:570:22: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/grpc_handler.py:602:28: SIM910 [*] Use `kwargs.get("param_name")` instead of `kwargs.get("param_name", None)`
+ pymilvus/client/grpc_handler.py:607:22: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/grpc_handler.py:667:22: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/grpc_handler.py:730:24: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/grpc_handler.py:749:24: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/grpc_handler.py:784:33: SIM910 [*] Use `kwargs.get("guarantee_timestamp")` instead of `kwargs.get("guarantee_timestamp", None)`
+ pymilvus/client/grpc_handler.py:820:33: SIM910 [*] Use `kwargs.get("guarantee_timestamp")` instead of `kwargs.get("guarantee_timestamp", None)`
+ pymilvus/client/grpc_handler.py:90:22: SIM910 [*] Use `kwargs.get("user")` instead of `kwargs.get("user", None)`
+ pymilvus/client/grpc_handler.py:92:36: SIM910 [*] Use `kwargs.get("db_name")` instead of `kwargs.get("db_name", None)`
+ pymilvus/client/grpc_handler.py:980:23: SIM910 [*] Use `kwargs.get("_callback")` instead of `kwargs.get("_callback", None)`
+ pymilvus/client/prepare.py:1052:17: SIM910 [*] Use `kwargs.get("limit")` instead of `kwargs.get("limit", None)`
+ pymilvus/client/prepare.py:1056:18: SIM910 [*] Use `kwargs.get("offset")` instead of `kwargs.get("offset", None)`
+ pymilvus/client/prepare.py:1135:25: SIM910 [*] Use `kwargs.get("channel_names")` instead of `kwargs.get("channel_names", None)`
+ pymilvus/client/prepare.py:813:12: SIM910 [*] Use `kwargs.get(RANK_GROUP_SCORER)` instead of `kwargs.get(RANK_GROUP_SCORER, None)`
+ pymilvus/client/prepare.py:822:12: SIM910 [*] Use `kwargs.get(GROUP_BY_FIELD)` instead of `kwargs.get(GROUP_BY_FIELD, None)`
+ pymilvus/client/prepare.py:831:12: SIM910 [*] Use `kwargs.get(GROUP_SIZE)` instead of `kwargs.get(GROUP_SIZE, None)`
+ pymilvus/client/prepare.py:840:12: SIM910 [*] Use `kwargs.get(GROUP_STRICT_SIZE)` instead of `kwargs.get(GROUP_STRICT_SIZE, None)`
+ pymilvus/client/prepare.py:92:26: SIM910 [*] Use `kwargs.get("num_partitions")` instead of `kwargs.get("num_partitions", None)`
+ pymilvus/decorators.py:170:21: SIM910 [*] Use `kwargs.get("log_level")` instead of `kwargs.get("log_level", None)`
+ pymilvus/decorators.py:171:22: SIM910 [*] Use `kwargs.get("client_request_id")` instead of `kwargs.get("client_request_id", None)`
+ pymilvus/decorators.py:56:24: SIM910 [*] Use `kwargs.get("timeout")` instead of `kwargs.get("timeout", None)`
+ pymilvus/decorators.py:57:28: SIM910 [*] Use `kwargs.get("retry_times")` instead of `kwargs.get("retry_times", None)`
+ pymilvus/orm/collection.py:188:51: SIM910 [*] Use `kwargs.get("auto_id")` instead of `kwargs.get("auto_id", None)`
+ pymilvus/orm/schema.py:324:30: SIM910 [*] Use `kwargs.get("default_value")` instead of `kwargs.get("default_value", None)`
... 3 additional changes omitted for project

mlflow/mlflow (+2 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

+ mlflow/openai/_openai_autolog.py:203:25: SIM910 [*] Use `kwargs.get("model")` instead of `kwargs.get("model", None)`
+ mlflow/pytorch/_pytorch_autolog.py:52:53: SIM910 [*] Use `kwargs.get("global_step")` instead of `kwargs.get("global_step", None)`

reflex-dev/reflex (+2 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

+ reflex/components/datadisplay/dataeditor.py:332:16: SIM910 [*] Use `props.get("rows")` instead of `props.get("rows", None)`
+ reflex/vars/base.py:242:24: SIM910 [*] Use `kwargs.get("_js_expr")` instead of `kwargs.get("_js_expr", None)`

zulip/zulip (+2 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview --select ALL

+ corporate/tests/test_stripe.py:652:41: SIM910 [*] Use `kwargs.get("remote_server_plan_start_date")` instead of `kwargs.get("remote_server_plan_start_date", None)`
+ zerver/lib/test_classes.py:1897:37: SIM910 [*] Use `kwargs.get("mentioned_user_group_id")` instead of `kwargs.get("mentioned_user_group_id", None)`

Changes by rule (2 rules affected)

code total + violation - violation + fix - fix
SIM910 49 49 0 0 0
SIM118 4 0 0 4 0

Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

crates/red_knot_python_semantic/src/types/infer.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@carljm carljm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

I think for these other types what we should do is create a Type::bool method (corresponding to the __bool__ magic method at runtime) that returns either BooleanLiteral (for those types whose Boolean value is statically known) or the bool builtin type. And then unary Not operator on most types will just call bool on the type and reverse it (if it's a BooleanLiteral.) Because we'll have other needs for the bool method outside unary Not.

@AlexWaygood AlexWaygood added the red-knot Multi-file analysis & type inference label Sep 25, 2024
Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following #13449 being merged, if you rebase this PR on main I think you can simplify this PR like so:

diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs
index d388fa8b2..33a22a378 100644
--- a/crates/red_knot_python_semantic/src/types.rs
+++ b/crates/red_knot_python_semantic/src/types.rs
@@ -936,7 +936,6 @@ impl Truthiness {
         matches!(self, Truthiness::Ambiguous)
     }
 
-    #[allow(unused)]
     const fn negate(self) -> Self {
         match self {
             Self::AlwaysTrue => Self::AlwaysFalse,
@@ -945,7 +944,6 @@ impl Truthiness {
         }
     }
 
-    #[allow(unused)]
     fn into_type(self, db: &dyn Db) -> Type {
         match self {
             Self::AlwaysTrue => Type::BooleanLiteral(true),
diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs
index 23ad71f3c..9b8362000 100644
--- a/crates/red_knot_python_semantic/src/types/infer.rs
+++ b/crates/red_knot_python_semantic/src/types/infer.rs
@@ -2210,11 +2210,7 @@ impl<'db> TypeInferenceBuilder<'db> {
 
         match (op, self.infer_expression(operand)) {
             (UnaryOp::USub, Type::IntLiteral(value)) => Type::IntLiteral(-value),
-            (UnaryOp::Not, Type::BooleanLiteral(value)) => Type::BooleanLiteral(!value),
-            (UnaryOp::Not, Type::IntLiteral(value)) => match value {
-                0 => Type::BooleanLiteral(true),
-                _ => Type::BooleanLiteral(false),
-            },
+            (UnaryOp::Not, ty) => ty.bool(self.db).negate().into_type(self.db),
             _ => Type::Unknown, // TODO other unary op types
         }
     }

but we'll also want to add a fair few tests, because we'll now be implementing not for all variants of Type rather than just one ;)

Copy link
Contributor Author

@haarisr haarisr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did most of the types that I could.

Would like help on tests for Type::Any | Type::Never | Type::Unknown | Type::Unbound

crates/red_knot_python_semantic/src/types/infer.rs Outdated Show resolved Hide resolved
@AlexWaygood AlexWaygood changed the title red-knot: Add not unary operator for integer literals red-knot: Implement the not operator for all Type variants Sep 25, 2024
Copy link
Contributor

@carljm carljm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! Just needs the failing test assertion commented out for now, with TODO comment.

crates/red_knot_python_semantic/src/types/infer.rs Outdated Show resolved Hide resolved
Co-authored-by: Carl Meyer <[email protected]>
@carljm carljm merged commit 7c83af4 into astral-sh:main Sep 25, 2024
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
red-knot Multi-file analysis & type inference
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants