From 28b48ab9029d84b5e9c8151259897208757925ed Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Mon, 18 Sep 2023 23:37:38 -0400 Subject: [PATCH] Avoid flagging starred expressions in UP007 (#7505) ## Summary These can't be fixed, because fixing them would lead to invalid syntax. So flagging them also feels misleading. Closes https://github.com/astral-sh/ruff/issues/7452. --- .../test/fixtures/pyupgrade/UP007.py | 6 ++++++ ...ff__rules__pyupgrade__tests__UP007.py.snap | 3 +++ .../src/analyze/typing.rs | 19 ++++++++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/crates/ruff/resources/test/fixtures/pyupgrade/UP007.py b/crates/ruff/resources/test/fixtures/pyupgrade/UP007.py index 3f8218f36c0223..5f23a92af2e8bb 100644 --- a/crates/ruff/resources/test/fixtures/pyupgrade/UP007.py +++ b/crates/ruff/resources/test/fixtures/pyupgrade/UP007.py @@ -108,3 +108,9 @@ class ServiceRefOrValue: # Regression test for: https://github.com/astral-sh/ruff/issues/7201 class ServiceRefOrValue: service_specification: Optional[str]is not True = None + + +# Regression test for: https://github.com/astral-sh/ruff/issues/7452 +class Collection(Protocol[*_B0]): + def __iter__(self) -> Iterator[Union[*_B0]]: + ... diff --git a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP007.py.snap b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP007.py.snap index e93227555cf313..a78faedf87b40e 100644 --- a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP007.py.snap +++ b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP007.py.snap @@ -410,5 +410,8 @@ UP007.py:110:28: UP007 [*] Use `X | Y` for type annotations 109 109 | class ServiceRefOrValue: 110 |- service_specification: Optional[str]is not True = None 110 |+ service_specification: str | None is not True = None +111 111 | +112 112 | +113 113 | # Regression test for: https://github.com/astral-sh/ruff/issues/7452 diff --git a/crates/ruff_python_semantic/src/analyze/typing.rs b/crates/ruff_python_semantic/src/analyze/typing.rs index 7c75dbb1813bc2..b7847f78dabb66 100644 --- a/crates/ruff_python_semantic/src/analyze/typing.rs +++ b/crates/ruff_python_semantic/src/analyze/typing.rs @@ -143,7 +143,7 @@ pub fn to_pep604_operator( slice: &Expr, semantic: &SemanticModel, ) -> Option { - /// Returns `true` if any argument in the slice is a quoted annotation). + /// Returns `true` if any argument in the slice is a quoted annotation. fn quoted_annotation(slice: &Expr) -> bool { match slice { Expr::Constant(ast::ExprConstant { @@ -155,6 +155,15 @@ pub fn to_pep604_operator( } } + /// Returns `true` if any argument in the slice is a starred expression. + fn starred_annotation(slice: &Expr) -> bool { + match slice { + Expr::Starred(_) => true, + Expr::Tuple(ast::ExprTuple { elts, .. }) => elts.iter().any(starred_annotation), + _ => false, + } + } + // If the slice is a forward reference (e.g., `Optional["Foo"]`), it can only be rewritten // if we're in a typing-only context. // @@ -175,6 +184,14 @@ pub fn to_pep604_operator( } } + // If any of the elements are starred expressions, we can't rewrite the subscript: + // ```python + // def f(x: Union[*int, str]): ... + // ``` + if starred_annotation(slice) { + return None; + } + semantic .resolve_call_path(value) .as_ref()