Skip to content

Commit ff677a9

Browse files
authored
[ruff] Recognize t-strings, generators, and lambdas in invalid-index-type (RUF016) (#20213)
## Summary Fixes #20204 Recognize t-strings, generators, and lambdas in RUF016 - Accept boolean literals as valid index and slice bounds. - Add TString, Generator, and Lambda to `CheckableExprType`. - Expand RUF016.py fixture and update snapshots accordingly.
1 parent b6bd32d commit ff677a9

File tree

3 files changed

+58
-2
lines changed

3 files changed

+58
-2
lines changed

crates/ruff_linter/resources/test/fixtures/ruff/RUF016.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,18 @@ def func():
113113
x = "x"
114114
var = [1, 2, 3][0:x]
115115
var = [1, 2, 3][x:1]
116+
117+
# https://github.com/astral-sh/ruff/issues/20204
118+
119+
# Should not emit for boolean index and slice bounds
120+
var = [1, 2, 3][False]
121+
var = [1, 2, 3][False:True:True]
122+
123+
# Should emit for invalid access using t-string
124+
var = [1, 2][t"x"]
125+
126+
# Should emit for invalid access using lambda
127+
var = [1, 2, 3][lambda: 0]
128+
129+
# Should emit for invalid access using generator
130+
var = [1, 2, 3][(x for x in ())]

crates/ruff_linter/src/rules/ruff/rules/invalid_index_type.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ pub(crate) fn invalid_index_type(checker: &Checker, expr: &ExprSubscript) {
8989

9090
if index_type.is_literal() {
9191
// If the index is a literal, require an integer
92-
if index_type != CheckableExprType::IntLiteral {
92+
if index_type != CheckableExprType::IntLiteral
93+
&& index_type != CheckableExprType::BooleanLiteral
94+
{
9395
checker.report_diagnostic(
9496
InvalidIndexType {
9597
value_type: value_type.to_string(),
@@ -111,7 +113,9 @@ pub(crate) fn invalid_index_type(checker: &Checker, expr: &ExprSubscript) {
111113
// If the index is a slice, require integer or null bounds
112114
if !matches!(
113115
is_slice_type,
114-
CheckableExprType::IntLiteral | CheckableExprType::NoneLiteral
116+
CheckableExprType::IntLiteral
117+
| CheckableExprType::NoneLiteral
118+
| CheckableExprType::BooleanLiteral
115119
) {
116120
checker.report_diagnostic(
117121
InvalidIndexType {
@@ -154,6 +158,7 @@ pub(crate) fn invalid_index_type(checker: &Checker, expr: &ExprSubscript) {
154158
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
155159
enum CheckableExprType {
156160
FString,
161+
TString,
157162
StringLiteral,
158163
BytesLiteral,
159164
IntLiteral,
@@ -170,12 +175,15 @@ enum CheckableExprType {
170175
Dict,
171176
Tuple,
172177
Slice,
178+
Generator,
179+
Lambda,
173180
}
174181

175182
impl fmt::Display for CheckableExprType {
176183
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
177184
match self {
178185
Self::FString => f.write_str("str"),
186+
Self::TString => f.write_str("Template"),
179187
Self::StringLiteral => f.write_str("str"),
180188
Self::BytesLiteral => f.write_str("bytes"),
181189
Self::IntLiteral => f.write_str("int"),
@@ -192,6 +200,8 @@ impl fmt::Display for CheckableExprType {
192200
Self::Slice => f.write_str("slice"),
193201
Self::Dict => f.write_str("dict"),
194202
Self::Tuple => f.write_str("tuple"),
203+
Self::Generator => f.write_str("generator"),
204+
Self::Lambda => f.write_str("lambda"),
195205
}
196206
}
197207
}
@@ -209,6 +219,7 @@ impl CheckableExprType {
209219
Expr::BooleanLiteral(_) => Some(Self::BooleanLiteral),
210220
Expr::NoneLiteral(_) => Some(Self::NoneLiteral),
211221
Expr::EllipsisLiteral(_) => Some(Self::EllipsisLiteral),
222+
Expr::TString(_) => Some(Self::TString),
212223
Expr::FString(_) => Some(Self::FString),
213224
Expr::List(_) => Some(Self::List),
214225
Expr::ListComp(_) => Some(Self::ListComp),
@@ -218,6 +229,8 @@ impl CheckableExprType {
218229
Expr::Dict(_) => Some(Self::Dict),
219230
Expr::Tuple(_) => Some(Self::Tuple),
220231
Expr::Slice(_) => Some(Self::Slice),
232+
Expr::Generator(_) => Some(Self::Generator),
233+
Expr::Lambda(_) => Some(Self::Lambda),
221234
_ => None,
222235
}
223236
}

crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF016_RUF016.py.snap

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,3 +415,31 @@ RUF016 Indexed access to type `list` uses type `str` instead of an integer or sl
415415
95 |
416416
96 | # Cannot emit on invalid access using variable in index
417417
|
418+
419+
RUF016 Indexed access to type `list` uses type `Template` instead of an integer or slice
420+
--> RUF016.py:124:14
421+
|
422+
123 | # Should emit for invalid access using t-string
423+
124 | var = [1, 2][t"x"]
424+
| ^^^^
425+
125 |
426+
126 | # Should emit for invalid access using lambda
427+
|
428+
429+
RUF016 Indexed access to type `list` uses type `lambda` instead of an integer or slice
430+
--> RUF016.py:127:17
431+
|
432+
126 | # Should emit for invalid access using lambda
433+
127 | var = [1, 2, 3][lambda: 0]
434+
| ^^^^^^^^^
435+
128 |
436+
129 | # Should emit for invalid access using generator
437+
|
438+
439+
RUF016 Indexed access to type `list` uses type `generator` instead of an integer or slice
440+
--> RUF016.py:130:17
441+
|
442+
129 | # Should emit for invalid access using generator
443+
130 | var = [1, 2, 3][(x for x in ())]
444+
| ^^^^^^^^^^^^^^^
445+
|

0 commit comments

Comments
 (0)