[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.
This commit is contained in:
Takayuki Maeda 2025-09-13 03:37:02 +09:00 committed by GitHub
parent b6bd32d9dc
commit ff677a96e4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 58 additions and 2 deletions

View file

@ -113,3 +113,18 @@ var = bytearray(b"abc")["x"]
x = "x"
var = [1, 2, 3][0:x]
var = [1, 2, 3][x:1]
# https://github.com/astral-sh/ruff/issues/20204
# Should not emit for boolean index and slice bounds
var = [1, 2, 3][False]
var = [1, 2, 3][False:True:True]
# Should emit for invalid access using t-string
var = [1, 2][t"x"]
# Should emit for invalid access using lambda
var = [1, 2, 3][lambda: 0]
# Should emit for invalid access using generator
var = [1, 2, 3][(x for x in ())]

View file

@ -89,7 +89,9 @@ pub(crate) fn invalid_index_type(checker: &Checker, expr: &ExprSubscript) {
if index_type.is_literal() {
// If the index is a literal, require an integer
if index_type != CheckableExprType::IntLiteral {
if index_type != CheckableExprType::IntLiteral
&& index_type != CheckableExprType::BooleanLiteral
{
checker.report_diagnostic(
InvalidIndexType {
value_type: value_type.to_string(),
@ -111,7 +113,9 @@ pub(crate) fn invalid_index_type(checker: &Checker, expr: &ExprSubscript) {
// If the index is a slice, require integer or null bounds
if !matches!(
is_slice_type,
CheckableExprType::IntLiteral | CheckableExprType::NoneLiteral
CheckableExprType::IntLiteral
| CheckableExprType::NoneLiteral
| CheckableExprType::BooleanLiteral
) {
checker.report_diagnostic(
InvalidIndexType {
@ -154,6 +158,7 @@ pub(crate) fn invalid_index_type(checker: &Checker, expr: &ExprSubscript) {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum CheckableExprType {
FString,
TString,
StringLiteral,
BytesLiteral,
IntLiteral,
@ -170,12 +175,15 @@ enum CheckableExprType {
Dict,
Tuple,
Slice,
Generator,
Lambda,
}
impl fmt::Display for CheckableExprType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::FString => f.write_str("str"),
Self::TString => f.write_str("Template"),
Self::StringLiteral => f.write_str("str"),
Self::BytesLiteral => f.write_str("bytes"),
Self::IntLiteral => f.write_str("int"),
@ -192,6 +200,8 @@ impl fmt::Display for CheckableExprType {
Self::Slice => f.write_str("slice"),
Self::Dict => f.write_str("dict"),
Self::Tuple => f.write_str("tuple"),
Self::Generator => f.write_str("generator"),
Self::Lambda => f.write_str("lambda"),
}
}
}
@ -209,6 +219,7 @@ impl CheckableExprType {
Expr::BooleanLiteral(_) => Some(Self::BooleanLiteral),
Expr::NoneLiteral(_) => Some(Self::NoneLiteral),
Expr::EllipsisLiteral(_) => Some(Self::EllipsisLiteral),
Expr::TString(_) => Some(Self::TString),
Expr::FString(_) => Some(Self::FString),
Expr::List(_) => Some(Self::List),
Expr::ListComp(_) => Some(Self::ListComp),
@ -218,6 +229,8 @@ impl CheckableExprType {
Expr::Dict(_) => Some(Self::Dict),
Expr::Tuple(_) => Some(Self::Tuple),
Expr::Slice(_) => Some(Self::Slice),
Expr::Generator(_) => Some(Self::Generator),
Expr::Lambda(_) => Some(Self::Lambda),
_ => None,
}
}

View file

@ -415,3 +415,31 @@ RUF016 Indexed access to type `list` uses type `str` instead of an integer or sl
95 |
96 | # Cannot emit on invalid access using variable in index
|
RUF016 Indexed access to type `list` uses type `Template` instead of an integer or slice
--> RUF016.py:124:14
|
123 | # Should emit for invalid access using t-string
124 | var = [1, 2][t"x"]
| ^^^^
125 |
126 | # Should emit for invalid access using lambda
|
RUF016 Indexed access to type `list` uses type `lambda` instead of an integer or slice
--> RUF016.py:127:17
|
126 | # Should emit for invalid access using lambda
127 | var = [1, 2, 3][lambda: 0]
| ^^^^^^^^^
128 |
129 | # Should emit for invalid access using generator
|
RUF016 Indexed access to type `list` uses type `generator` instead of an integer or slice
--> RUF016.py:130:17
|
129 | # Should emit for invalid access using generator
130 | var = [1, 2, 3][(x for x in ())]
| ^^^^^^^^^^^^^^^
|