mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-17 00:50:16 +00:00
[flake8-pyi
] Implement PYI062
(duplicate-literal-member
) (#11269)
This commit is contained in:
parent
1a392d34e1
commit
56b4c47d74
12 changed files with 451 additions and 0 deletions
|
@ -418,6 +418,49 @@ where
|
|||
inner(func, semantic, expr, None);
|
||||
}
|
||||
|
||||
/// Traverse a "literal" type annotation, applying `func` to each literal member.
|
||||
///
|
||||
/// The function is called with each expression in the literal (excluding declarations of nested
|
||||
/// literals) and the parent expression.
|
||||
pub fn traverse_literal<'a, F>(func: &mut F, semantic: &SemanticModel, expr: &'a Expr)
|
||||
where
|
||||
F: FnMut(&'a Expr, &'a Expr),
|
||||
{
|
||||
fn inner<'a, F>(
|
||||
func: &mut F,
|
||||
semantic: &SemanticModel,
|
||||
expr: &'a Expr,
|
||||
parent: Option<&'a Expr>,
|
||||
) where
|
||||
F: FnMut(&'a Expr, &'a Expr),
|
||||
{
|
||||
// Ex) Literal[x, y]
|
||||
if let Expr::Subscript(ast::ExprSubscript { value, slice, .. }) = expr {
|
||||
if semantic.match_typing_expr(value, "Literal") {
|
||||
match &**slice {
|
||||
Expr::Tuple(ast::ExprTuple { elts, .. }) => {
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
other => {
|
||||
inner(func, semantic, other, Some(expr));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Otherwise, call the function on expression, if it's not the top-level expression.
|
||||
if let Some(parent) = parent {
|
||||
func(expr, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner(func, semantic, expr, None);
|
||||
}
|
||||
|
||||
/// Abstraction for a type checker, conservatively checks for the intended type(s).
|
||||
pub trait TypeChecker {
|
||||
/// Check annotation expression to match the intended type(s).
|
||||
|
|
|
@ -1350,6 +1350,15 @@ impl<'a> SemanticModel<'a> {
|
|||
false
|
||||
}
|
||||
|
||||
/// Return `true` if the model is in a nested literal expression (e.g., the inner `Literal` in
|
||||
/// `Literal[Literal[int, str], float]`).
|
||||
pub fn in_nested_literal(&self) -> bool {
|
||||
// Ex) `Literal[Literal[int, str], float]`
|
||||
self.current_expression_grandparent()
|
||||
.and_then(Expr::as_subscript_expr)
|
||||
.is_some_and(|parent| self.match_typing_expr(&parent.value, "Literal"))
|
||||
}
|
||||
|
||||
/// Returns `true` if `left` and `right` are in the same branches of an `if`, `match`, or
|
||||
/// `try` statement.
|
||||
///
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue