From aa0db338d935aa40fafaa05feff7343c42491d8e Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 12 Aug 2024 11:39:28 +0100 Subject: [PATCH] Implement `iter()`, `len()` and `is_empty()` for all display-literal AST nodes (#12807) --- crates/ruff_linter/src/checkers/ast/mod.rs | 4 +- crates/ruff_linter/src/fix/edits.rs | 9 +- .../rules/fastapi_redundant_response_model.rs | 26 +++--- .../rules/flake8_bandit/rules/django_extra.rs | 10 +-- .../flake8_bandit/rules/shell_injection.rs | 6 +- .../flake8_bugbear/rules/duplicate_value.rs | 12 +-- .../rules/reuse_of_groupby_generator.rs | 6 +- .../rules/static_key_dict_comprehension.rs | 2 +- .../rules/unnecessary_generator_dict.rs | 6 +- .../unnecessary_list_comprehension_dict.rs | 4 +- .../rules/unnecessary_literal_dict.rs | 2 +- .../rules/multiple_starts_ends_with.rs | 4 +- .../rules/reimplemented_container_builtin.rs | 6 +- .../rules/unnecessary_dict_kwargs.rs | 4 +- .../flake8_pie/rules/unnecessary_spread.rs | 2 +- .../rules/bad_generator_return_type.rs | 5 +- .../rules/redundant_literal_union.rs | 4 +- .../rules/flake8_pyi/rules/simple_defaults.rs | 6 +- .../rules/unnecessary_literal_union.rs | 16 ++-- .../rules/unrecognized_version_info.rs | 8 +- .../flake8_pytest_style/rules/parametrize.rs | 8 +- .../flake8_simplify/rules/ast_bool_op.rs | 7 +- .../flake8_simplify/rules/yoda_conditions.rs | 8 +- .../rules/manual_dict_comprehension.rs | 12 +-- .../rules/pydoclint/rules/check_docstring.rs | 2 +- .../src/rules/pyflakes/rules/assert_tuple.rs | 6 +- .../src/rules/pyflakes/rules/if_tuple.rs | 6 +- .../src/rules/pyflakes/rules/repeated_keys.rs | 4 +- .../src/rules/pyflakes/rules/strings.rs | 6 +- .../pylint/rules/dict_iter_missing_items.rs | 23 ++--- .../rules/pylint/rules/iteration_over_set.rs | 8 +- .../pylint/rules/redeclared_assigned_name.rs | 4 +- .../pylint/rules/self_assigning_variable.rs | 9 +- ...convert_named_tuple_functional_to_class.rs | 7 +- .../rules/pyupgrade/rules/os_error_alias.rs | 16 ++-- .../rules/printf_string_formatting.rs | 4 +- .../pyupgrade/rules/timeout_error_alias.rs | 16 ++-- .../pyupgrade/rules/use_pep604_annotation.rs | 2 +- .../pyupgrade/rules/use_pep604_isinstance.rs | 10 +-- .../pyupgrade/rules/yield_in_for_loop.rs | 7 +- .../refurb/rules/isinstance_type_none.rs | 2 +- .../refurb/rules/reimplemented_operator.rs | 3 +- .../refurb/rules/reimplemented_starmap.rs | 9 +- ...rectly_parenthesized_tuple_in_subscript.rs | 8 +- .../src/rules/ruff/rules/never_union.rs | 14 +-- .../ruff/rules/quadratic_list_summation.rs | 2 +- .../src/rules/ruff/rules/sort_dunder_all.rs | 9 +- .../src/rules/ruff/rules/sort_dunder_slots.rs | 19 ++-- crates/ruff_linter/src/rules/ruff/typing.rs | 2 +- crates/ruff_python_ast/src/helpers.rs | 12 +-- crates/ruff_python_ast/src/nodes.rs | 90 +++++++++++++++++++ crates/ruff_python_codegen/src/generator.rs | 28 +++--- .../src/expression/expr_tuple.rs | 2 +- .../src/expression/mod.rs | 10 +-- .../src/analyze/typing.rs | 23 ++--- crates/ruff_python_semantic/src/model.rs | 4 +- 56 files changed, 304 insertions(+), 240 deletions(-) diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index 61cdfb3d8758b..8e8a5f04f4b46 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -1290,8 +1290,8 @@ impl<'a> Visitor<'a> for Checker<'a> { let Keyword { arg, value, .. } = keyword; match (arg.as_ref(), value) { // Ex) NamedTuple("a", **{"a": int}) - (None, Expr::Dict(ast::ExprDict { items, .. })) => { - for ast::DictItem { key, value } in items { + (None, Expr::Dict(dict)) => { + for ast::DictItem { key, value } in dict { if let Some(key) = key.as_ref() { self.visit_non_type_definition(key); self.visit_type_definition(value); diff --git a/crates/ruff_linter/src/fix/edits.rs b/crates/ruff_linter/src/fix/edits.rs index 5cadc38c874d6..98a27280176ee 100644 --- a/crates/ruff_linter/src/fix/edits.rs +++ b/crates/ruff_linter/src/fix/edits.rs @@ -151,16 +151,15 @@ pub(crate) fn add_to_dunder_all<'a>( stylist: &Stylist, ) -> Vec { let (insertion_point, export_prefix_length) = match expr { - Expr::List(ExprList { elts, range, .. }) => ( - elts.last() - .map_or(range.end() - "]".text_len(), Ranged::end), + Expr::List(ExprList { elts, .. }) => ( + elts.last().map_or(expr.end() - "]".text_len(), Ranged::end), elts.len(), ), Expr::Tuple(tup) if tup.parenthesized => ( tup.elts .last() .map_or(tup.end() - ")".text_len(), Ranged::end), - tup.elts.len(), + tup.len(), ), Expr::Tuple(tup) if !tup.parenthesized => ( tup.elts @@ -168,7 +167,7 @@ pub(crate) fn add_to_dunder_all<'a>( .expect("unparenthesized empty tuple is not possible") .range() .end(), - tup.elts.len(), + tup.len(), ), _ => { // we don't know how to insert into this expression diff --git a/crates/ruff_linter/src/rules/fastapi/rules/fastapi_redundant_response_model.rs b/crates/ruff_linter/src/rules/fastapi/rules/fastapi_redundant_response_model.rs index b2fcad67c9d60..538949cbe19f0 100644 --- a/crates/ruff_linter/src/rules/fastapi/rules/fastapi_redundant_response_model.rs +++ b/crates/ruff_linter/src/rules/fastapi/rules/fastapi_redundant_response_model.rs @@ -122,17 +122,15 @@ fn is_identical_types( return_value: &Expr, semantic: &SemanticModel, ) -> bool { - if let (Some(response_mode_name_expr), Some(return_value_name_expr)) = ( - response_model_arg.as_name_expr(), - return_value.as_name_expr(), - ) { + if let (Expr::Name(response_mode_name_expr), Expr::Name(return_value_name_expr)) = + (response_model_arg, return_value) + { return semantic.resolve_name(response_mode_name_expr) == semantic.resolve_name(return_value_name_expr); } - if let (Some(response_mode_subscript), Some(return_value_subscript)) = ( - response_model_arg.as_subscript_expr(), - return_value.as_subscript_expr(), - ) { + if let (Expr::Subscript(response_mode_subscript), Expr::Subscript(return_value_subscript)) = + (response_model_arg, return_value) + { return is_identical_types( &response_mode_subscript.value, &return_value_subscript.value, @@ -143,15 +141,13 @@ fn is_identical_types( semantic, ); } - if let (Some(response_mode_tuple), Some(return_value_tuple)) = ( - response_model_arg.as_tuple_expr(), - return_value.as_tuple_expr(), - ) { - return response_mode_tuple.elts.len() == return_value_tuple.elts.len() + if let (Expr::Tuple(response_mode_tuple), Expr::Tuple(return_value_tuple)) = + (response_model_arg, return_value) + { + return response_mode_tuple.len() == return_value_tuple.len() && response_mode_tuple - .elts .iter() - .zip(return_value_tuple.elts.iter()) + .zip(return_value_tuple) .all(|(x, y)| is_identical_types(x, y, semantic)); } false diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/django_extra.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/django_extra.rs index acfdea1bacd0c..8c872a32540fa 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/django_extra.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/django_extra.rs @@ -1,6 +1,6 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{self as ast, Expr, ExprAttribute, ExprDict, ExprList}; +use ruff_python_ast::{self as ast, Expr, ExprAttribute}; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -65,8 +65,8 @@ fn is_call_insecure(call: &ast::ExprCall) -> bool { if let Some(argument) = call.arguments.find_argument(argument_name, position) { match argument_name { "select" => match argument { - Expr::Dict(ExprDict { items, .. }) => { - if items.iter().any(|ast::DictItem { key, value }| { + Expr::Dict(dict) => { + if dict.iter().any(|ast::DictItem { key, value }| { key.as_ref() .is_some_and(|key| !key.is_string_literal_expr()) || !value.is_string_literal_expr() @@ -77,8 +77,8 @@ fn is_call_insecure(call: &ast::ExprCall) -> bool { _ => return true, }, "where" | "tables" => match argument { - Expr::List(ExprList { elts, .. }) => { - if !elts.iter().all(Expr::is_string_literal_expr) { + Expr::List(list) => { + if !list.iter().all(Expr::is_string_literal_expr) { return true; } } diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/shell_injection.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/shell_injection.rs index 272ada6db09b1..ff2330b623eba 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/shell_injection.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/shell_injection.rs @@ -530,11 +530,11 @@ fn is_partial_path(expr: &Expr) -> bool { /// subprocess.Popen(["/usr/local/bin/rsync", "*", "some_where:"], shell=True) /// ``` fn is_wildcard_command(expr: &Expr) -> bool { - if let Expr::List(ast::ExprList { elts, .. }) = expr { + if let Expr::List(list) = expr { let mut has_star = false; let mut has_command = false; - for elt in elts { - if let Some(text) = string_literal(elt) { + for item in list { + if let Some(text) = string_literal(item) { has_star |= text.contains('*'); has_command |= text.contains("chown") || text.contains("chmod") diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/rules/duplicate_value.rs b/crates/ruff_linter/src/rules/flake8_bugbear/rules/duplicate_value.rs index 3abc90c2e281c..3021c7053fdaf 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/rules/duplicate_value.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/rules/duplicate_value.rs @@ -49,16 +49,16 @@ impl Violation for DuplicateValue { /// B033 pub(crate) fn duplicate_value(checker: &mut Checker, set: &ast::ExprSet) { let mut seen_values: FxHashSet = FxHashSet::default(); - for (index, elt) in set.elts.iter().enumerate() { - if elt.is_literal_expr() { - let comparable_value: ComparableExpr = elt.into(); + for (index, value) in set.iter().enumerate() { + if value.is_literal_expr() { + let comparable_value = ComparableExpr::from(value); if !seen_values.insert(comparable_value) { let mut diagnostic = Diagnostic::new( DuplicateValue { - value: checker.generator().expr(elt), + value: checker.generator().expr(value), }, - elt.range(), + value.range(), ); diagnostic.try_set_fix(|| { @@ -73,7 +73,7 @@ pub(crate) fn duplicate_value(checker: &mut Checker, set: &ast::ExprSet) { /// Remove the member at the given index from the [`ast::ExprSet`]. fn remove_member(set: &ast::ExprSet, index: usize, source: &str) -> Result { - if index < set.elts.len() - 1 { + if index < set.len() - 1 { // Case 1: the expression is _not_ the last node, so delete from the start of the // expression to the end of the subsequent comma. // Ex) Delete `"a"` in `{"a", "b", "c"}`. diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/rules/reuse_of_groupby_generator.rs b/crates/ruff_linter/src/rules/flake8_bugbear/rules/reuse_of_groupby_generator.rs index b495276c02449..c9deccbfc6418 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/rules/reuse_of_groupby_generator.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/rules/reuse_of_groupby_generator.rs @@ -315,15 +315,15 @@ pub(crate) fn reuse_of_groupby_generator( let Expr::Call(ast::ExprCall { func, .. }) = &iter else { return; }; - let Expr::Tuple(ast::ExprTuple { elts, .. }) = target else { + let Expr::Tuple(tuple) = target else { // Ignore any `groupby()` invocation that isn't unpacked return; }; - if elts.len() != 2 { + if tuple.len() != 2 { return; } // We have an invocation of groupby which is a simple unpacking - let Expr::Name(ast::ExprName { id: group_name, .. }) = &elts[1] else { + let Expr::Name(ast::ExprName { id: group_name, .. }) = &tuple.elts[1] else { return; }; // Check if the function call is `itertools.groupby` diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/rules/static_key_dict_comprehension.rs b/crates/ruff_linter/src/rules/flake8_bugbear/rules/static_key_dict_comprehension.rs index 1da5864e0927d..a19c22ec238f6 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/rules/static_key_dict_comprehension.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/rules/static_key_dict_comprehension.rs @@ -72,7 +72,7 @@ pub(crate) fn static_key_dict_comprehension(checker: &mut Checker, dict_comp: &a /// comprehension. fn is_constant(key: &Expr, names: &FxHashMap<&str, &ast::ExprName>) -> bool { match key { - Expr::Tuple(ast::ExprTuple { elts, .. }) => elts.iter().all(|elt| is_constant(elt, names)), + Expr::Tuple(tuple) => tuple.iter().all(|elem| is_constant(elem, names)), Expr::Name(ast::ExprName { id, .. }) => !names.contains_key(id.as_str()), Expr::Attribute(ast::ExprAttribute { value, .. }) => is_constant(value, names), Expr::Subscript(ast::ExprSubscript { value, slice, .. }) => { diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_generator_dict.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_generator_dict.rs index 4e72a558ad95f..9d368a3da07b2 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_generator_dict.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_generator_dict.rs @@ -61,13 +61,13 @@ pub(crate) fn unnecessary_generator_dict( let Expr::Generator(ast::ExprGenerator { elt, .. }) = argument else { return; }; - let Expr::Tuple(ast::ExprTuple { elts, .. }) = elt.as_ref() else { + let Expr::Tuple(tuple) = &**elt else { return; }; - if elts.len() != 2 { + if tuple.len() != 2 { return; } - if elts.iter().any(Expr::is_starred_expr) { + if tuple.iter().any(Expr::is_starred_expr) { return; } let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorDict, expr.range()); diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs index 2e0c11ee50db4..ef109a8f174d9 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs @@ -62,10 +62,10 @@ pub(crate) fn unnecessary_list_comprehension_dict( let Expr::ListComp(ast::ExprListComp { elt, .. }) = argument else { return; }; - let Expr::Tuple(ast::ExprTuple { elts, .. }) = elt.as_ref() else { + let Expr::Tuple(tuple) = &**elt else { return; }; - if elts.len() != 2 { + if tuple.len() != 2 { return; } let mut diagnostic = Diagnostic::new(UnnecessaryListComprehensionDict, expr.range()); diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_dict.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_dict.rs index 7c885b2f7e49a..d7a6032b58a61 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_dict.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_dict.rs @@ -74,7 +74,7 @@ pub(crate) fn unnecessary_literal_dict( // Accept `dict((1, 2), ...))` `dict([(1, 2), ...])`. if !elts .iter() - .all(|elt| matches!(&elt, Expr::Tuple(ast::ExprTuple { elts, .. }) if elts.len() == 2)) + .all(|elt| matches!(&elt, Expr::Tuple(tuple) if tuple.len() == 2)) { return; } diff --git a/crates/ruff_linter/src/rules/flake8_pie/rules/multiple_starts_ends_with.rs b/crates/ruff_linter/src/rules/flake8_pie/rules/multiple_starts_ends_with.rs index 477dd1efee7da..6eaee62631ac0 100644 --- a/crates/ruff_linter/src/rules/flake8_pie/rules/multiple_starts_ends_with.rs +++ b/crates/ruff_linter/src/rules/flake8_pie/rules/multiple_starts_ends_with.rs @@ -163,8 +163,8 @@ pub(crate) fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) { elts: words .iter() .flat_map(|value| { - if let Expr::Tuple(ast::ExprTuple { elts, .. }) = value { - Left(elts.iter()) + if let Expr::Tuple(tuple) = value { + Left(tuple.iter()) } else { Right(iter::once(*value)) } diff --git a/crates/ruff_linter/src/rules/flake8_pie/rules/reimplemented_container_builtin.rs b/crates/ruff_linter/src/rules/flake8_pie/rules/reimplemented_container_builtin.rs index 730bb8415804c..c085d235d1568 100644 --- a/crates/ruff_linter/src/rules/flake8_pie/rules/reimplemented_container_builtin.rs +++ b/crates/ruff_linter/src/rules/flake8_pie/rules/reimplemented_container_builtin.rs @@ -1,4 +1,4 @@ -use ruff_python_ast::{self as ast, Expr, ExprLambda}; +use ruff_python_ast::{Expr, ExprLambda}; use ruff_diagnostics::{Diagnostic, Edit, Fix}; use ruff_diagnostics::{FixAvailability, Violation}; @@ -70,8 +70,8 @@ pub(crate) fn reimplemented_container_builtin(checker: &mut Checker, expr: &Expr } let container = match &**body { - Expr::List(ast::ExprList { elts, .. }) if elts.is_empty() => Container::List, - Expr::Dict(ast::ExprDict { items, .. }) if items.is_empty() => Container::Dict, + Expr::List(list) if list.is_empty() => Container::List, + Expr::Dict(dict) if dict.is_empty() => Container::Dict, _ => return, }; let mut diagnostic = Diagnostic::new(ReimplementedContainerBuiltin { container }, expr.range()); diff --git a/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs b/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs index 236d339b80709..4bffddb94acde 100644 --- a/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs +++ b/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs @@ -87,13 +87,13 @@ pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, call: &ast::ExprCal .iter_keys() .filter_map(|key| key.and_then(as_kwarg)) .collect(); - if kwargs.len() != dict.items.len() { + if kwargs.len() != dict.len() { continue; } let mut diagnostic = Diagnostic::new(UnnecessaryDictKwargs, keyword.range()); - if dict.items.is_empty() { + if dict.is_empty() { diagnostic.try_set_fix(|| { remove_argument( keyword, diff --git a/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_spread.rs b/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_spread.rs index 0fd2a96c5f7dd..e4987dc4b5a6e 100644 --- a/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_spread.rs +++ b/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_spread.rs @@ -49,7 +49,7 @@ impl Violation for UnnecessarySpread { pub(crate) fn unnecessary_spread(checker: &mut Checker, dict: &ast::ExprDict) { // The first "end" is the start of the dictionary, immediately following the open bracket. let mut prev_end = dict.start() + TextSize::from(1); - for ast::DictItem { key, value } in &dict.items { + for ast::DictItem { key, value } in dict { if key.is_none() { // We only care about when the key is None which indicates a spread `**` // inside a dict. diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/bad_generator_return_type.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/bad_generator_return_type.rs index 4427a643351c6..1406bb4bd2073 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/bad_generator_return_type.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/bad_generator_return_type.rs @@ -162,12 +162,11 @@ pub(crate) fn bad_generator_return_type( // - if not, don't emit the diagnostic let yield_type_info = match returns { ast::Expr::Subscript(ast::ExprSubscript { slice, .. }) => match slice.as_ref() { - ast::Expr::Tuple(slice_tuple @ ast::ExprTuple { .. }) => { + ast::Expr::Tuple(slice_tuple) => { if !slice_tuple - .elts .iter() .skip(1) - .all(|elt| is_any_or_none(elt, semantic)) + .all(|element| is_any_or_none(element, semantic)) { return; } diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/redundant_literal_union.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/redundant_literal_union.rs index f22fd0db9043e..dfb28cb9bc025 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/redundant_literal_union.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/redundant_literal_union.rs @@ -67,8 +67,8 @@ pub(crate) fn redundant_literal_union<'a>(checker: &mut Checker, union: &'a Expr let mut func = |expr: &'a Expr, _parent: &'a Expr| { if let Expr::Subscript(ast::ExprSubscript { value, slice, .. }) = expr { if checker.semantic().match_typing_expr(value, "Literal") { - if let Expr::Tuple(ast::ExprTuple { elts, .. }) = slice.as_ref() { - typing_literal_exprs.extend(elts.iter()); + if let Expr::Tuple(tuple) = &**slice { + typing_literal_exprs.extend(tuple); } else { typing_literal_exprs.push(slice); } diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/simple_defaults.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/simple_defaults.rs index 9f40e350a6778..e14246f0e5de6 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/simple_defaults.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/simple_defaults.rs @@ -298,10 +298,10 @@ fn is_valid_default_value_with_annotation( .iter() .all(|e| is_valid_default_value_with_annotation(e, false, locator, semantic)); } - Expr::Dict(ast::ExprDict { items, range: _ }) => { + Expr::Dict(dict) => { return allow_container - && items.len() <= 10 - && items.iter().all(|ast::DictItem { key, value }| { + && dict.len() <= 10 + && dict.iter().all(|ast::DictItem { key, value }| { key.as_ref().is_some_and(|key| { is_valid_default_value_with_annotation(key, false, locator, semantic) }) && is_valid_default_value_with_annotation(value, false, locator, semantic) diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_literal_union.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_literal_union.rs index af40e2f6bae44..da0c2383b30b5 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_literal_union.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_literal_union.rs @@ -70,19 +70,15 @@ pub(crate) fn unnecessary_literal_union<'a>(checker: &mut Checker, expr: &'a Exp literal_subscript = Some(value.as_ref()); } + let slice = &**slice; + // flatten already-unioned literals to later union again - if let Expr::Tuple(ast::ExprTuple { - elts, - range: _, - ctx: _, - parenthesized: _, - }) = slice.as_ref() - { - for expr in elts { - literal_exprs.push(expr); + if let Expr::Tuple(tuple) = slice { + for item in tuple { + literal_exprs.push(item); } } else { - literal_exprs.push(slice.as_ref()); + literal_exprs.push(slice); } } } else { diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/unrecognized_version_info.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/unrecognized_version_info.rs index aad888aafb82b..cfefc15d2d303 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/unrecognized_version_info.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/unrecognized_version_info.rs @@ -181,7 +181,7 @@ fn version_check( } // Tuple comparison, e.g., `sys.version_info == (3, 4)`. - let Expr::Tuple(ast::ExprTuple { elts, .. }) = comparator else { + let Expr::Tuple(tuple) = comparator else { if checker.enabled(Rule::UnrecognizedVersionInfoCheck) { checker .diagnostics @@ -190,7 +190,7 @@ fn version_check( return; }; - if !elts.iter().all(is_int_constant) { + if !tuple.iter().all(is_int_constant) { // All tuple elements must be integers, e.g., `sys.version_info == (3, 4)` instead of // `sys.version_info == (3.0, 4)`. if checker.enabled(Rule::UnrecognizedVersionInfoCheck) { @@ -198,7 +198,7 @@ fn version_check( .diagnostics .push(Diagnostic::new(UnrecognizedVersionInfoCheck, test.range())); } - } else if elts.len() > 2 { + } else if tuple.len() > 2 { // Must compare against major and minor version only, e.g., `sys.version_info == (3, 4)` // instead of `sys.version_info == (3, 4, 0)`. if checker.enabled(Rule::PatchVersionComparison) { @@ -216,7 +216,7 @@ fn version_check( _ => return, }; - if elts.len() != expected_length { + if tuple.len() != expected_length { checker.diagnostics.push(Diagnostic::new( WrongTupleLengthVersionComparison { expected_length }, test.range(), diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs index b93ccbb58e26e..317d1babdb3cc 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs @@ -416,9 +416,7 @@ fn check_names(checker: &mut Checker, decorator: &Decorator, expr: &Expr) { } Expr::Tuple(ast::ExprTuple { elts, .. }) => { if elts.len() == 1 { - if let Some(first) = elts.first() { - handle_single_name(checker, expr, first); - } + handle_single_name(checker, expr, &elts[0]); } else { match names_type { types::ParametrizeNameType::Tuple => {} @@ -462,9 +460,7 @@ fn check_names(checker: &mut Checker, decorator: &Decorator, expr: &Expr) { } Expr::List(ast::ExprList { elts, .. }) => { if elts.len() == 1 { - if let Some(first) = elts.first() { - handle_single_name(checker, expr, first); - } + handle_single_name(checker, expr, &elts[0]); } else { match names_type { types::ParametrizeNameType::List => {} diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_bool_op.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_bool_op.rs index 43c7d93f943c1..f7d8c3b924d81 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_bool_op.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_bool_op.rs @@ -411,8 +411,8 @@ pub(crate) fn duplicate_isinstance_call(checker: &mut Checker, expr: &Expr) { elts: types .iter() .flat_map(|value| { - if let Expr::Tuple(ast::ExprTuple { elts, .. }) = value { - Left(elts.iter()) + if let Expr::Tuple(tuple) = value { + Left(tuple.iter()) } else { Right(iter::once(*value)) } @@ -722,8 +722,7 @@ fn get_short_circuit_edit( generator.expr(expr) }; Edit::range_replacement( - if matches!(expr, Expr::Tuple(ast::ExprTuple { elts, ctx: _, range: _, parenthesized: _}) if !elts.is_empty()) - { + if matches!(expr, Expr::Tuple(tuple) if !tuple.is_empty()) { format!("({content})") } else { content diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/yoda_conditions.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/yoda_conditions.rs index a623a7ec36318..0bacecda83469 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/rules/yoda_conditions.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/yoda_conditions.rs @@ -91,18 +91,18 @@ impl From<&Expr> for ConstantLikelihood { ConstantLikelihood::from_identifier(attr) } Expr::Name(ast::ExprName { id, .. }) => ConstantLikelihood::from_identifier(id), - Expr::Tuple(ast::ExprTuple { elts, .. }) => elts + Expr::Tuple(tuple) => tuple .iter() .map(ConstantLikelihood::from) .min() .unwrap_or(ConstantLikelihood::Definitely), - Expr::List(ast::ExprList { elts, .. }) => elts + Expr::List(list) => list .iter() .map(ConstantLikelihood::from) .min() .unwrap_or(ConstantLikelihood::Definitely), - Expr::Dict(ast::ExprDict { items, .. }) => { - if items.is_empty() { + Expr::Dict(dict) => { + if dict.is_empty() { ConstantLikelihood::Definitely } else { ConstantLikelihood::Probably diff --git a/crates/ruff_linter/src/rules/perflint/rules/manual_dict_comprehension.rs b/crates/ruff_linter/src/rules/perflint/rules/manual_dict_comprehension.rs index 352bcafe5803e..aa150e2db4866 100644 --- a/crates/ruff_linter/src/rules/perflint/rules/manual_dict_comprehension.rs +++ b/crates/ruff_linter/src/rules/perflint/rules/manual_dict_comprehension.rs @@ -102,16 +102,16 @@ pub(crate) fn manual_dict_comprehension(checker: &mut Checker, target: &Expr, bo }; match target { - Expr::Tuple(ast::ExprTuple { elts, .. }) => { - if !elts + Expr::Tuple(tuple) => { + if !tuple .iter() - .any(|elt| ComparableExpr::from(slice) == ComparableExpr::from(elt)) + .any(|element| ComparableExpr::from(slice) == ComparableExpr::from(element)) { return; } - if !elts + if !tuple .iter() - .any(|elt| ComparableExpr::from(value) == ComparableExpr::from(elt)) + .any(|element| ComparableExpr::from(value) == ComparableExpr::from(element)) { return; } @@ -128,7 +128,7 @@ pub(crate) fn manual_dict_comprehension(checker: &mut Checker, target: &Expr, bo } // Exclude non-dictionary value. - let Some(name) = subscript_value.as_name_expr() else { + let Expr::Name(name) = &**subscript_value else { return; }; let Some(binding) = checker diff --git a/crates/ruff_linter/src/rules/pydoclint/rules/check_docstring.rs b/crates/ruff_linter/src/rules/pydoclint/rules/check_docstring.rs index 30d3ed6e1c933..53c9899383e79 100644 --- a/crates/ruff_linter/src/rules/pydoclint/rules/check_docstring.rs +++ b/crates/ruff_linter/src/rules/pydoclint/rules/check_docstring.rs @@ -613,7 +613,7 @@ impl<'a> Visitor<'a> for BodyVisitor<'a> { }; if let ast::Expr::Tuple(tuple) = exceptions { - for exception in &tuple.elts { + for exception in tuple { maybe_store_exception(exception); } } else { diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/assert_tuple.rs b/crates/ruff_linter/src/rules/pyflakes/rules/assert_tuple.rs index 0fde7fb5aed01..e8af1828afc08 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/assert_tuple.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/assert_tuple.rs @@ -1,4 +1,4 @@ -use ruff_python_ast::{self as ast, Expr, Stmt}; +use ruff_python_ast::{Expr, Stmt}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; @@ -39,8 +39,8 @@ impl Violation for AssertTuple { /// F631 pub(crate) fn assert_tuple(checker: &mut Checker, stmt: &Stmt, test: &Expr) { - if let Expr::Tuple(ast::ExprTuple { elts, .. }) = &test { - if !elts.is_empty() { + if let Expr::Tuple(tuple) = &test { + if !tuple.is_empty() { checker .diagnostics .push(Diagnostic::new(AssertTuple, stmt.range())); diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/if_tuple.rs b/crates/ruff_linter/src/rules/pyflakes/rules/if_tuple.rs index 540065a6b968d..2d97e68d07f77 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/if_tuple.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/if_tuple.rs @@ -1,4 +1,4 @@ -use ruff_python_ast::{self as ast, Expr, StmtIf}; +use ruff_python_ast::{Expr, StmtIf}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; @@ -41,10 +41,10 @@ impl Violation for IfTuple { /// F634 pub(crate) fn if_tuple(checker: &mut Checker, stmt_if: &StmtIf) { for branch in if_elif_branches(stmt_if) { - let Expr::Tuple(ast::ExprTuple { elts, .. }) = &branch.test else { + let Expr::Tuple(tuple) = &branch.test else { continue; }; - if elts.is_empty() { + if tuple.is_empty() { continue; } checker diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/repeated_keys.rs b/crates/ruff_linter/src/rules/pyflakes/rules/repeated_keys.rs index f3f4d7907a23f..06ef03d97f4f6 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/repeated_keys.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/repeated_keys.rs @@ -130,10 +130,10 @@ impl Violation for MultiValueRepeatedKeyVariable { pub(crate) fn repeated_keys(checker: &mut Checker, dict: &ast::ExprDict) { // Generate a map from key to (index, value). let mut seen: FxHashMap> = - FxHashMap::with_capacity_and_hasher(dict.items.len(), FxBuildHasher); + FxHashMap::with_capacity_and_hasher(dict.len(), FxBuildHasher); // Detect duplicate keys. - for (i, ast::DictItem { key, value }) in dict.items.iter().enumerate() { + for (i, ast::DictItem { key, value }) in dict.iter().enumerate() { let Some(key) = key else { continue; }; diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/strings.rs b/crates/ruff_linter/src/rules/pyflakes/rules/strings.rs index 755d0c4c31e12..4a296de44e845 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/strings.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/strings.rs @@ -690,10 +690,10 @@ pub(crate) fn percent_format_positional_count_mismatch( return; } - if let Expr::Tuple(ast::ExprTuple { elts, .. }) = right { + if let Expr::Tuple(tuple) = right { let mut found = 0; - for elt in elts { - if elt.is_starred_expr() { + for element in tuple { + if element.is_starred_expr() { return; } found += 1; diff --git a/crates/ruff_linter/src/rules/pylint/rules/dict_iter_missing_items.rs b/crates/ruff_linter/src/rules/pylint/rules/dict_iter_missing_items.rs index 03016aa5ca0d1..2af5085d8991f 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/dict_iter_missing_items.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/dict_iter_missing_items.rs @@ -1,4 +1,4 @@ -use ruff_python_ast::{Expr, ExprTuple}; +use ruff_python_ast::{Expr, Stmt}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; @@ -49,15 +49,15 @@ impl AlwaysFixableViolation for DictIterMissingItems { } pub(crate) fn dict_iter_missing_items(checker: &mut Checker, target: &Expr, iter: &Expr) { - let Expr::Tuple(ExprTuple { elts, .. }) = target else { + let Expr::Tuple(tuple) = target else { return; }; - if elts.len() != 2 { + if tuple.len() != 2 { return; }; - let Some(name) = iter.as_name_expr() else { + let Expr::Name(name) = iter else { return; }; @@ -91,20 +91,15 @@ fn is_dict_key_tuple_with_two_elements(binding: &Binding, semantic: &SemanticMod return false; }; - let Some(assign_stmt) = statement.as_assign_stmt() else { + let Stmt::Assign(assign_stmt) = statement else { return false; }; - let Some(dict_expr) = assign_stmt.value.as_dict_expr() else { + let Expr::Dict(dict_expr) = &*assign_stmt.value else { return false; }; - dict_expr.iter_keys().all(|elt| { - elt.is_some_and(|x| { - if let Expr::Tuple(ExprTuple { elts, .. }) = x { - return elts.len() == 2; - } - false - }) - }) + dict_expr + .iter_keys() + .all(|key| matches!(key, Some(Expr::Tuple(tuple)) if tuple.len() == 2)) } diff --git a/crates/ruff_linter/src/rules/pylint/rules/iteration_over_set.rs b/crates/ruff_linter/src/rules/pylint/rules/iteration_over_set.rs index 647f0d8c5d3eb..82023c5ad8320 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/iteration_over_set.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/iteration_over_set.rs @@ -1,6 +1,6 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{self as ast, Expr}; +use ruff_python_ast::Expr; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -42,17 +42,17 @@ impl AlwaysFixableViolation for IterationOverSet { /// PLC0208 pub(crate) fn iteration_over_set(checker: &mut Checker, expr: &Expr) { - let Expr::Set(ast::ExprSet { elts, .. }) = expr else { + let Expr::Set(set) = expr else { return; }; - if elts.iter().any(Expr::is_starred_expr) { + if set.iter().any(Expr::is_starred_expr) { return; } let mut diagnostic = Diagnostic::new(IterationOverSet, expr.range()); - let tuple = if let [elt] = elts.as_slice() { + let tuple = if let [elt] = set.elts.as_slice() { let elt = checker.locator().slice(elt); format!("({elt},)") } else { diff --git a/crates/ruff_linter/src/rules/pylint/rules/redeclared_assigned_name.rs b/crates/ruff_linter/src/rules/pylint/rules/redeclared_assigned_name.rs index 5952a462695f9..a2380e59d4c9d 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/redeclared_assigned_name.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/redeclared_assigned_name.rs @@ -52,8 +52,8 @@ pub(crate) fn redeclared_assigned_name(checker: &mut Checker, targets: &Vec) { match expr { - Expr::Tuple(ast::ExprTuple { elts, .. }) => { - for target in elts { + Expr::Tuple(tuple) => { + for target in tuple { check_expr(checker, target, names); } } diff --git a/crates/ruff_linter/src/rules/pylint/rules/self_assigning_variable.rs b/crates/ruff_linter/src/rules/pylint/rules/self_assigning_variable.rs index 68875a9eb57c2..b90cdc80d5826 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/self_assigning_variable.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/self_assigning_variable.rs @@ -71,13 +71,10 @@ pub(crate) fn self_annotated_assignment(checker: &mut Checker, assign: &ast::Stm fn visit_assignments(left: &Expr, right: &Expr, diagnostics: &mut Vec) { match (left, right) { - ( - Expr::Tuple(ast::ExprTuple { elts: lhs_elts, .. }), - Expr::Tuple(ast::ExprTuple { elts: rhs_elts, .. }), - ) if lhs_elts.len() == rhs_elts.len() => lhs_elts + (Expr::Tuple(lhs), Expr::Tuple(rhs)) if lhs.len() == rhs.len() => lhs .iter() - .zip(rhs_elts.iter()) - .for_each(|(lhs, rhs)| visit_assignments(lhs, rhs, diagnostics)), + .zip(rhs) + .for_each(|(lhs_elem, rhs_elem)| visit_assignments(lhs_elem, rhs_elem, diagnostics)), ( Expr::Name(ast::ExprName { id: lhs_name, .. }), Expr::Name(ast::ExprName { id: rhs_name, .. }), diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs index ab39ca1bfe36b..971b02beb307b 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs @@ -169,14 +169,15 @@ fn create_field_assignment_stmt(field: Name, annotation: &Expr) -> Stmt { /// Create a list of field assignments from the `NamedTuple` fields argument. fn create_fields_from_fields_arg(fields: &Expr) -> Option> { - let ast::ExprList { elts, .. } = fields.as_list_expr()?; - if elts.is_empty() { + let fields = fields.as_list_expr()?; + if fields.is_empty() { let node = Stmt::Pass(ast::StmtPass { range: TextRange::default(), }); Some(vec![node]) } else { - elts.iter() + fields + .iter() .map(|field| { let ast::ExprTuple { elts, .. } = field.as_tuple_expr()?; let [field, annotation] = elts.as_slice() else { diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/os_error_alias.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/os_error_alias.rs index 677eaa57c4879..6fa5d99a774e4 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/os_error_alias.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/os_error_alias.rs @@ -98,22 +98,20 @@ fn tuple_diagnostic(checker: &mut Checker, tuple: &ast::ExprTuple, aliases: &[&E if semantic.has_builtin_binding("OSError") { // Filter out any `OSErrors` aliases. let mut remaining: Vec = tuple - .elts .iter() - .filter_map(|elt| { - if aliases.contains(&elt) { + .filter_map(|element| { + if aliases.contains(&element) { None } else { - Some(elt.clone()) + Some(element.clone()) } }) .collect(); // If `OSError` itself isn't already in the tuple, add it. if tuple - .elts .iter() - .all(|elt| !semantic.match_builtin_expr(elt, "OSError")) + .all(|elem| !semantic.match_builtin_expr(elem, "OSError")) { let node = ast::ExprName { id: Name::new_static("OSError"), @@ -159,9 +157,9 @@ pub(crate) fn os_error_alias_handlers(checker: &mut Checker, handlers: &[ExceptH Expr::Tuple(tuple) => { // List of aliases to replace with `OSError`. let mut aliases: Vec<&Expr> = vec![]; - for elt in &tuple.elts { - if is_alias(elt, checker.semantic()) { - aliases.push(elt); + for element in tuple { + if is_alias(element, checker.semantic()) { + aliases.push(element); } } if !aliases.is_empty() { diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/printf_string_formatting.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/printf_string_formatting.rs index 6c45ac8307679..aa5700617d860 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/printf_string_formatting.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/printf_string_formatting.rs @@ -198,8 +198,8 @@ fn percent_to_format(format_string: &CFormatString) -> String { /// If a tuple has one argument, remove the comma; otherwise, return it as-is. fn clean_params_tuple<'a>(right: &Expr, locator: &Locator<'a>) -> Cow<'a, str> { - if let Expr::Tuple(ast::ExprTuple { elts, .. }) = &right { - if elts.len() == 1 { + if let Expr::Tuple(tuple) = &right { + if tuple.len() == 1 { if !locator.contains_line_break(right.range()) { let mut contents = locator.slice(right).to_string(); for (i, character) in contents.chars().rev().enumerate() { diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/timeout_error_alias.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/timeout_error_alias.rs index 97ee95df9c877..4f5c421471c7e 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/timeout_error_alias.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/timeout_error_alias.rs @@ -110,22 +110,20 @@ fn tuple_diagnostic(checker: &mut Checker, tuple: &ast::ExprTuple, aliases: &[&E if semantic.has_builtin_binding("TimeoutError") { // Filter out any `TimeoutErrors` aliases. let mut remaining: Vec = tuple - .elts .iter() - .filter_map(|elt| { - if aliases.contains(&elt) { + .filter_map(|element| { + if aliases.contains(&element) { None } else { - Some(elt.clone()) + Some(element.clone()) } }) .collect(); // If `TimeoutError` itself isn't already in the tuple, add it. if tuple - .elts .iter() - .all(|elt| !semantic.match_builtin_expr(elt, "TimeoutError")) + .all(|element| !semantic.match_builtin_expr(element, "TimeoutError")) { let node = ast::ExprName { id: Name::new_static("TimeoutError"), @@ -171,9 +169,9 @@ pub(crate) fn timeout_error_alias_handlers(checker: &mut Checker, handlers: &[Ex Expr::Tuple(tuple) => { // List of aliases to replace with `TimeoutError`. let mut aliases: Vec<&Expr> = vec![]; - for elt in &tuple.elts { - if is_alias(elt, checker.semantic(), checker.settings.target_version) { - aliases.push(elt); + for element in tuple { + if is_alias(element, checker.semantic(), checker.settings.target_version) { + aliases.push(element); } } if !aliases.is_empty() { diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs index a33f2bbc231f3..d46167028da67 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs @@ -189,7 +189,7 @@ fn is_allowed_value(expr: &Expr) -> bool { | Expr::Subscript(_) | Expr::Name(_) | Expr::List(_) => true, - Expr::Tuple(tuple) => tuple.elts.iter().all(is_allowed_value), + Expr::Tuple(tuple) => tuple.iter().all(is_allowed_value), // Maybe require parentheses. Expr::Named(_) => false, // Invalid in binary expressions. diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_isinstance.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_isinstance.rs index 4c6d7ef37881a..92db5e57b1e5f 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_isinstance.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_isinstance.rs @@ -3,7 +3,7 @@ use std::fmt; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::pep_604_union; -use ruff_python_ast::{self as ast, Expr}; +use ruff_python_ast::Expr; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -90,15 +90,15 @@ pub(crate) fn use_pep604_isinstance( let Some(types) = args.get(1) else { return; }; - let Expr::Tuple(ast::ExprTuple { elts, .. }) = types else { + let Expr::Tuple(tuple) = types else { return; }; // Ex) `()` - if elts.is_empty() { + if tuple.is_empty() { return; } // Ex) `(*args,)` - if elts.iter().any(Expr::is_starred_expr) { + if tuple.iter().any(Expr::is_starred_expr) { return; } let Some(builtin_function_name) = checker.semantic().resolve_builtin_symbol(func) else { @@ -110,7 +110,7 @@ pub(crate) fn use_pep604_isinstance( checker.diagnostics.push( Diagnostic::new(NonPEP604Isinstance { kind }, expr.range()).with_fix(Fix::unsafe_edit( Edit::range_replacement( - checker.generator().expr(&pep_604_union(elts)), + checker.generator().expr(&pep_604_union(&tuple.elts)), types.range(), ), )), diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/yield_in_for_loop.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/yield_in_for_loop.rs index a7fc89910817b..8e0b9448812c0 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/yield_in_for_loop.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/yield_in_for_loop.rs @@ -135,11 +135,10 @@ fn is_same_expr(left: &Expr, right: &Expr) -> bool { match (&left, &right) { (Expr::Name(left), Expr::Name(right)) => left.id == right.id, (Expr::Tuple(left), Expr::Tuple(right)) => { - left.elts.len() == right.elts.len() + left.len() == right.len() && left - .elts .iter() - .zip(right.elts.iter()) + .zip(right) .all(|(left, right)| is_same_expr(left, right)) } _ => false, @@ -153,7 +152,7 @@ fn collect_names<'a>(expr: &'a Expr) -> Box expr.as_name_expr().into_iter().chain( expr.as_tuple_expr() .into_iter() - .flat_map(|tuple| tuple.elts.iter().flat_map(collect_names)), + .flat_map(|tuple| tuple.iter().flat_map(collect_names)), ), ) } diff --git a/crates/ruff_linter/src/rules/refurb/rules/isinstance_type_none.rs b/crates/ruff_linter/src/rules/refurb/rules/isinstance_type_none.rs index 4692674b0327a..7fe233b55459d 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/isinstance_type_none.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/isinstance_type_none.rs @@ -98,7 +98,7 @@ fn is_none(expr: &Expr) -> bool { } // Ex) `(type(None),)` - Expr::Tuple(ast::ExprTuple { elts, .. }) => elts.iter().all(|elt| inner(elt, false)), + Expr::Tuple(tuple) => tuple.iter().all(|element| inner(element, false)), // Ex) `type(None) | type(None)` Expr::BinOp(ast::ExprBinOp { diff --git a/crates/ruff_linter/src/rules/refurb/rules/reimplemented_operator.rs b/crates/ruff_linter/src/rules/refurb/rules/reimplemented_operator.rs index f33b903e68f68..8d550e22d18cb 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/reimplemented_operator.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/reimplemented_operator.rs @@ -254,13 +254,12 @@ fn itemgetter_op_tuple( let [arg] = params.args.as_slice() else { return None; }; - if expr.elts.is_empty() || expr.elts.len() == 1 { + if expr.len() <= 1 { return None; } Some(Operator { name: "itemgetter", args: expr - .elts .iter() .map(|expr| { expr.as_subscript_expr() diff --git a/crates/ruff_linter/src/rules/refurb/rules/reimplemented_starmap.rs b/crates/ruff_linter/src/rules/refurb/rules/reimplemented_starmap.rs index 1d47662dc3e69..8c92005e195c6 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/reimplemented_starmap.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/reimplemented_starmap.rs @@ -134,9 +134,9 @@ pub(crate) fn reimplemented_starmap(checker: &mut Checker, target: &StarmapCandi } // Ex) `f(x, y, z) for x, y, z in iter` ComprehensionTarget::Tuple(tuple) => { - if tuple.elts.len() != args.len() - || !std::iter::zip(&tuple.elts, args) - .all(|(x, y)| ComparableExpr::from(x) == ComparableExpr::from(y)) + if tuple.len() != args.len() + || std::iter::zip(tuple, args) + .any(|(x, y)| ComparableExpr::from(x) != ComparableExpr::from(y)) { return; } @@ -144,9 +144,8 @@ pub(crate) fn reimplemented_starmap(checker: &mut Checker, target: &StarmapCandi // If any of the members are used outside the function call, we can't replace it. if any_over_expr(func, &|expr| { tuple - .elts .iter() - .any(|elt| ComparableExpr::from(expr) == ComparableExpr::from(elt)) + .any(|elem| ComparableExpr::from(expr) == ComparableExpr::from(elem)) }) { return; } diff --git a/crates/ruff_linter/src/rules/ruff/rules/incorrectly_parenthesized_tuple_in_subscript.rs b/crates/ruff_linter/src/rules/ruff/rules/incorrectly_parenthesized_tuple_in_subscript.rs index 028173455e8b8..a0b7b0552ef56 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/incorrectly_parenthesized_tuple_in_subscript.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/incorrectly_parenthesized_tuple_in_subscript.rs @@ -63,16 +63,16 @@ impl AlwaysFixableViolation for IncorrectlyParenthesizedTupleInSubscript { pub(crate) fn subscript_with_parenthesized_tuple(checker: &mut Checker, subscript: &ExprSubscript) { let prefer_parentheses = checker.settings.ruff.parenthesize_tuple_in_subscript; - let Some(tuple_subscript) = subscript.slice.as_tuple_expr() else { + let Expr::Tuple(tuple_subscript) = &*subscript.slice else { return; }; - if tuple_subscript.parenthesized == prefer_parentheses || tuple_subscript.elts.is_empty() { + if tuple_subscript.parenthesized == prefer_parentheses || tuple_subscript.is_empty() { return; } // Adding parentheses in the presence of a slice leads to a syntax error. - if prefer_parentheses && tuple_subscript.elts.iter().any(Expr::is_slice_expr) { + if prefer_parentheses && tuple_subscript.iter().any(Expr::is_slice_expr) { return; } @@ -82,7 +82,7 @@ pub(crate) fn subscript_with_parenthesized_tuple(checker: &mut Checker, subscrip // see https://peps.python.org/pep-0646/#change-1-star-expressions-in-indexes if checker.settings.target_version <= PythonVersion::Py310 && !prefer_parentheses - && tuple_subscript.elts.iter().any(Expr::is_starred_expr) + && tuple_subscript.iter().any(Expr::is_starred_expr) { return; } diff --git a/crates/ruff_linter/src/rules/ruff/rules/never_union.rs b/crates/ruff_linter/src/rules/ruff/rules/never_union.rs index c96c3ed5600d3..53b2641bb5b41 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/never_union.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/never_union.rs @@ -112,25 +112,19 @@ pub(crate) fn never_union(checker: &mut Checker, expr: &Expr) { ctx: _, range: _, }) if checker.semantic().match_typing_expr(value, "Union") => { - let Expr::Tuple(ast::ExprTuple { - elts, - ctx: _, - range: _, - parenthesized: _, - }) = slice.as_ref() - else { + let Expr::Tuple(tuple_slice) = &**slice else { return; }; // Analyze each element of the `Union`. - for elt in elts { + for elt in tuple_slice { if let Some(never_like) = NeverLike::from_expr(elt, checker.semantic()) { // Collect the other elements of the `Union`. - let rest = elts + let rest: Vec = tuple_slice .iter() .filter(|other| *other != elt) .cloned() - .collect::>(); + .collect(); // Ignore, e.g., `typing.Union[typing.NoReturn]`. if rest.is_empty() { diff --git a/crates/ruff_linter/src/rules/ruff/rules/quadratic_list_summation.rs b/crates/ruff_linter/src/rules/ruff/rules/quadratic_list_summation.rs index 1781d9e53a989..31b4396a2ac74 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/quadratic_list_summation.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/quadratic_list_summation.rs @@ -136,7 +136,7 @@ fn start_is_empty_list(arguments: &Arguments, semantic: &SemanticModel) -> bool Expr::Call(ast::ExprCall { func, arguments, .. }) => arguments.is_empty() && semantic.match_builtin_expr(func, "list"), - Expr::List(ast::ExprList { elts, ctx, .. }) => elts.is_empty() && ctx.is_load(), + Expr::List(list) => list.is_empty() && list.ctx.is_load(), _ => false, } } diff --git a/crates/ruff_linter/src/rules/ruff/rules/sort_dunder_all.rs b/crates/ruff_linter/src/rules/ruff/rules/sort_dunder_all.rs index 6b0ebbaaf4fc5..b63fb68bff046 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/sort_dunder_all.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/sort_dunder_all.rs @@ -157,11 +157,16 @@ fn sort_dunder_all(checker: &mut Checker, target: &ast::Expr, node: &ast::Expr) let (elts, range, kind) = match node { ast::Expr::List(ast::ExprList { elts, range, .. }) => (elts, *range, SequenceKind::List), - ast::Expr::Tuple(tuple_node @ ast::ExprTuple { elts, range, .. }) => ( + ast::Expr::Tuple(ast::ExprTuple { + elts, + range, + parenthesized, + .. + }) => ( elts, *range, SequenceKind::Tuple { - parenthesized: tuple_node.parenthesized, + parenthesized: *parenthesized, }, ), _ => return, diff --git a/crates/ruff_linter/src/rules/ruff/rules/sort_dunder_slots.rs b/crates/ruff_linter/src/rules/ruff/rules/sort_dunder_slots.rs index 210e69145fdcf..606b464e3672d 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/sort_dunder_slots.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/sort_dunder_slots.rs @@ -168,9 +168,14 @@ impl<'a> StringLiteralDisplay<'a> { kind, } } - ast::Expr::Tuple(tuple_node @ ast::ExprTuple { elts, range, .. }) => { + ast::Expr::Tuple(ast::ExprTuple { + elts, + range, + parenthesized, + .. + }) => { let kind = DisplayKind::Sequence(SequenceKind::Tuple { - parenthesized: tuple_node.parenthesized, + parenthesized: *parenthesized, }); Self { elts: Cow::Borrowed(elts), @@ -186,8 +191,8 @@ impl<'a> StringLiteralDisplay<'a> { kind, } } - ast::Expr::Dict(dict @ ast::ExprDict { items, range }) => { - let mut narrowed_keys = Vec::with_capacity(items.len()); + ast::Expr::Dict(dict) => { + let mut narrowed_keys = Vec::with_capacity(dict.len()); for key in dict.iter_keys() { if let Some(key) = key { // This is somewhat unfortunate, @@ -201,11 +206,11 @@ impl<'a> StringLiteralDisplay<'a> { // `__slots__ = {"foo": "bar", **other_dict}` // If `None` wasn't present in the keys, // the length of the keys should always equal the length of the values - assert_eq!(narrowed_keys.len(), items.len()); + assert_eq!(narrowed_keys.len(), dict.len()); Self { elts: Cow::Owned(narrowed_keys), - range: *range, - kind: DisplayKind::Dict { items }, + range: dict.range(), + kind: DisplayKind::Dict { items: &dict.items }, } } _ => return None, diff --git a/crates/ruff_linter/src/rules/ruff/typing.rs b/crates/ruff_linter/src/rules/ruff/typing.rs index e2e4dee557279..7b98b610f8540 100644 --- a/crates/ruff_linter/src/rules/ruff/typing.rs +++ b/crates/ruff_linter/src/rules/ruff/typing.rs @@ -23,7 +23,7 @@ fn is_known_type(qualified_name: &QualifiedName, minor_version: u8) -> bool { /// tuple, the iterator will only yield the slice. fn resolve_slice_value(slice: &Expr) -> impl Iterator { match slice { - Expr::Tuple(ast::ExprTuple { elts: elements, .. }) => Left(elements.iter()), + Expr::Tuple(tuple) => Left(tuple.iter()), _ => Right(std::iter::once(slice)), } } diff --git a/crates/ruff_python_ast/src/helpers.rs b/crates/ruff_python_ast/src/helpers.rs index 6613bd9dd0bf1..44b48c2b18257 100644 --- a/crates/ruff_python_ast/src/helpers.rs +++ b/crates/ruff_python_ast/src/helpers.rs @@ -582,8 +582,8 @@ pub const fn is_singleton(expr: &Expr) -> bool { /// Return `true` if the [`Expr`] is a literal or tuple of literals. pub fn is_constant(expr: &Expr) -> bool { - if let Expr::Tuple(ast::ExprTuple { elts, .. }) = expr { - elts.iter().all(is_constant) + if let Expr::Tuple(tuple) = expr { + tuple.iter().all(is_constant) } else { expr.is_literal_expr() } @@ -630,8 +630,8 @@ pub fn extract_handled_exceptions(handlers: &[ExceptHandler]) -> Vec<&Expr> { match handler { ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler { type_, .. }) => { if let Some(type_) = type_ { - if let Expr::Tuple(ast::ExprTuple { elts, .. }) = &type_.as_ref() { - for type_ in elts { + if let Expr::Tuple(tuple) = &**type_ { + for type_ in tuple { handled_exceptions.push(type_); } } else { @@ -1185,8 +1185,8 @@ impl Truthiness { Self::Truthy } } - Expr::Dict(ast::ExprDict { items, .. }) => { - if items.is_empty() { + Expr::Dict(dict) => { + if dict.is_empty() { Self::Falsey } else { Self::Truthy diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index 8861218153b3a..644d6c4ba7fbc 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -856,6 +856,27 @@ impl ExprDict { pub fn value(&self, n: usize) -> &Expr { self.items[n].value() } + + pub fn iter(&self) -> std::slice::Iter<'_, DictItem> { + self.items.iter() + } + + pub fn len(&self) -> usize { + self.items.len() + } + + pub fn is_empty(&self) -> bool { + self.items.is_empty() + } +} + +impl<'a> IntoIterator for &'a ExprDict { + type IntoIter = std::slice::Iter<'a, DictItem>; + type Item = &'a DictItem; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } } impl From for Expr { @@ -955,6 +976,29 @@ pub struct ExprSet { pub elts: Vec, } +impl ExprSet { + pub fn iter(&self) -> std::slice::Iter<'_, Expr> { + self.elts.iter() + } + + pub fn len(&self) -> usize { + self.elts.len() + } + + pub fn is_empty(&self) -> bool { + self.elts.is_empty() + } +} + +impl<'a> IntoIterator for &'a ExprSet { + type IntoIter = std::slice::Iter<'a, Expr>; + type Item = &'a Expr; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + impl From for Expr { fn from(payload: ExprSet) -> Self { Expr::Set(payload) @@ -2759,6 +2803,29 @@ pub struct ExprList { pub ctx: ExprContext, } +impl ExprList { + pub fn iter(&self) -> std::slice::Iter<'_, Expr> { + self.elts.iter() + } + + pub fn len(&self) -> usize { + self.elts.len() + } + + pub fn is_empty(&self) -> bool { + self.elts.is_empty() + } +} + +impl<'a> IntoIterator for &'a ExprList { + type IntoIter = std::slice::Iter<'a, Expr>; + type Item = &'a Expr; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + impl From for Expr { fn from(payload: ExprList) -> Self { Expr::List(payload) @@ -2776,6 +2843,29 @@ pub struct ExprTuple { pub parenthesized: bool, } +impl ExprTuple { + pub fn iter(&self) -> std::slice::Iter<'_, Expr> { + self.elts.iter() + } + + pub fn len(&self) -> usize { + self.elts.len() + } + + pub fn is_empty(&self) -> bool { + self.elts.is_empty() + } +} + +impl<'a> IntoIterator for &'a ExprTuple { + type IntoIter = std::slice::Iter<'a, Expr>; + type Item = &'a Expr; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + impl From for Expr { fn from(payload: ExprTuple) -> Self { Expr::Tuple(payload) diff --git a/crates/ruff_python_codegen/src/generator.rs b/crates/ruff_python_codegen/src/generator.rs index 01ff10a9ab42e..89d4702f8dd25 100644 --- a/crates/ruff_python_codegen/src/generator.rs +++ b/crates/ruff_python_codegen/src/generator.rs @@ -921,10 +921,10 @@ impl<'a> Generator<'a> { self.unparse_expr(orelse, precedence::IF_EXP); }); } - Expr::Dict(ast::ExprDict { items, range: _ }) => { + Expr::Dict(dict) => { self.p("{"); let mut first = true; - for ast::DictItem { key, value } in items { + for ast::DictItem { key, value } in dict { self.p_delim(&mut first, ", "); if let Some(key) = key { self.unparse_expr(key, precedence::COMMA); @@ -937,15 +937,15 @@ impl<'a> Generator<'a> { } self.p("}"); } - Expr::Set(ast::ExprSet { elts, range: _ }) => { - if elts.is_empty() { + Expr::Set(set) => { + if set.is_empty() { self.p("set()"); } else { self.p("{"); let mut first = true; - for v in elts { + for item in set { self.p_delim(&mut first, ", "); - self.unparse_expr(v, precedence::COMMA); + self.unparse_expr(item, precedence::COMMA); } self.p("}"); } @@ -1164,26 +1164,26 @@ impl<'a> Generator<'a> { self.unparse_expr(value, precedence::MAX); } Expr::Name(ast::ExprName { id, .. }) => self.p(id.as_str()), - Expr::List(ast::ExprList { elts, .. }) => { + Expr::List(list) => { self.p("["); let mut first = true; - for elt in elts { + for item in list { self.p_delim(&mut first, ", "); - self.unparse_expr(elt, precedence::COMMA); + self.unparse_expr(item, precedence::COMMA); } self.p("]"); } - Expr::Tuple(ast::ExprTuple { elts, .. }) => { - if elts.is_empty() { + Expr::Tuple(tuple) => { + if tuple.is_empty() { self.p("()"); } else { group_if!(precedence::TUPLE, { let mut first = true; - for elt in elts { + for item in tuple { self.p_delim(&mut first, ", "); - self.unparse_expr(elt, precedence::COMMA); + self.unparse_expr(item, precedence::COMMA); } - self.p_if(elts.len() == 1, ","); + self.p_if(tuple.len() == 1, ","); }); } } diff --git a/crates/ruff_python_formatter/src/expression/expr_tuple.rs b/crates/ruff_python_formatter/src/expression/expr_tuple.rs index f386b23ba6a2e..7ca6ac0ccde5f 100644 --- a/crates/ruff_python_formatter/src/expression/expr_tuple.rs +++ b/crates/ruff_python_formatter/src/expression/expr_tuple.rs @@ -193,7 +193,7 @@ impl FormatNodeRule for FormatExprTuple { TupleParentheses::NeverPreserve => { optional_parentheses(&ExprSequence::new(item)).fmt(f) } - TupleParentheses::OptionalParentheses if item.elts.len() == 2 => { + TupleParentheses::OptionalParentheses if item.len() == 2 => { optional_parentheses(&ExprSequence::new(item)).fmt(f) } TupleParentheses::Default | TupleParentheses::OptionalParentheses => { diff --git a/crates/ruff_python_formatter/src/expression/mod.rs b/crates/ruff_python_formatter/src/expression/mod.rs index 0e2e76adba207..39b216b823ce3 100644 --- a/crates/ruff_python_formatter/src/expression/mod.rs +++ b/crates/ruff_python_formatter/src/expression/mod.rs @@ -1052,7 +1052,7 @@ pub(crate) fn has_own_parentheses( .. }, ) => { - if !tuple.elts.is_empty() || context.comments().has_dangling(AnyNodeRef::from(expr)) { + if !tuple.is_empty() || context.comments().has_dangling(AnyNodeRef::from(expr)) { Some(OwnParentheses::NonEmpty) } else { Some(OwnParentheses::Empty) @@ -1216,10 +1216,10 @@ pub(crate) fn is_splittable_expression(expr: &Expr, context: &PyFormatContext) - | Expr::YieldFrom(_) => true, // Sequence types can split if they contain at least one element. - Expr::Tuple(tuple) => !tuple.elts.is_empty(), - Expr::Dict(dict) => !dict.items.is_empty(), - Expr::Set(set) => !set.elts.is_empty(), - Expr::List(list) => !list.elts.is_empty(), + Expr::Tuple(tuple) => !tuple.is_empty(), + Expr::Dict(dict) => !dict.is_empty(), + Expr::Set(set) => !set.is_empty(), + Expr::List(list) => !list.is_empty(), Expr::UnaryOp(unary) => is_splittable_expression(unary.operand.as_ref(), context), Expr::Yield(ast::ExprYield { value, .. }) => value.is_some(), diff --git a/crates/ruff_python_semantic/src/analyze/typing.rs b/crates/ruff_python_semantic/src/analyze/typing.rs index 08875307d0c98..1a76c60ab4345 100644 --- a/crates/ruff_python_semantic/src/analyze/typing.rs +++ b/crates/ruff_python_semantic/src/analyze/typing.rs @@ -151,7 +151,7 @@ pub fn to_pep604_operator( fn quoted_annotation(slice: &Expr) -> bool { match slice { Expr::StringLiteral(_) => true, - Expr::Tuple(ast::ExprTuple { elts, .. }) => elts.iter().any(quoted_annotation), + Expr::Tuple(tuple) => tuple.iter().any(quoted_annotation), _ => false, } } @@ -160,7 +160,7 @@ pub fn to_pep604_operator( fn starred_annotation(slice: &Expr) -> bool { match slice { Expr::Starred(_) => true, - Expr::Tuple(ast::ExprTuple { elts, .. }) => elts.iter().any(starred_annotation), + Expr::Tuple(tuple) => tuple.iter().any(starred_annotation), _ => false, } } @@ -237,9 +237,9 @@ pub fn is_immutable_annotation( if is_immutable_generic_type(qualified_name.segments()) { true } else if matches!(qualified_name.segments(), ["typing", "Union"]) { - if let Expr::Tuple(ast::ExprTuple { elts, .. }) = slice.as_ref() { - elts.iter().all(|elt| { - is_immutable_annotation(elt, semantic, extend_immutable_calls) + if let Expr::Tuple(tuple) = &**slice { + tuple.iter().all(|element| { + is_immutable_annotation(element, semantic, extend_immutable_calls) }) } else { false @@ -399,11 +399,12 @@ where // Ex) Union[x, y] if let Expr::Subscript(ast::ExprSubscript { value, slice, .. }) = expr { if semantic.match_typing_expr(value, "Union") { - if let Expr::Tuple(ast::ExprTuple { elts, .. }) = slice.as_ref() { + if let Expr::Tuple(tuple) = &**slice { // Traverse each element of the tuple within the union recursively to handle cases // such as `Union[..., Union[...]] - elts.iter() - .for_each(|elt| inner(func, semantic, elt, Some(expr))); + tuple + .iter() + .for_each(|elem| inner(func, semantic, elem, Some(expr))); return; } } @@ -438,11 +439,11 @@ where if let Expr::Subscript(ast::ExprSubscript { value, slice, .. }) = expr { if semantic.match_typing_expr(value, "Literal") { match &**slice { - Expr::Tuple(ast::ExprTuple { elts, .. }) => { + Expr::Tuple(tuple) => { // Traverse each element of the tuple within the literal recursively to handle cases // such as `Literal[..., Literal[...]] - for elt in elts { - inner(func, semantic, elt, Some(expr)); + for element in tuple { + inner(func, semantic, element, Some(expr)); } } other => { diff --git a/crates/ruff_python_semantic/src/model.rs b/crates/ruff_python_semantic/src/model.rs index 184fb9496b0b0..7ef179b51a9d9 100644 --- a/crates/ruff_python_semantic/src/model.rs +++ b/crates/ruff_python_semantic/src/model.rs @@ -1432,9 +1432,7 @@ impl<'a> SemanticModel<'a> { /// variable to be "used" if it's shadowed by another variable with usages. pub fn is_unused(&self, expr: &Expr) -> bool { match expr { - Expr::Tuple(ast::ExprTuple { elts, .. }) => { - elts.iter().all(|expr| self.is_unused(expr)) - } + Expr::Tuple(tuple) => tuple.iter().all(|expr| self.is_unused(expr)), Expr::Name(ast::ExprName { id, .. }) => { // Treat a variable as used if it has any usages, _or_ it's shadowed by another variable // with usages.