Skip to content

Commit

Permalink
Avoid false-positives for runtime-types in type checking blocks (#2863)
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Feb 13, 2023
1 parent 7be17c5 commit aeae63b
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from typing import Final, Literal, TypeAlias

RatingKey: TypeAlias = Literal["good", "fair", "poor"]

RATING_KEYS: Final[tuple[RatingKey, ...]] = ("good", "fair", "poor")
23 changes: 14 additions & 9 deletions crates/ruff/src/checkers/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ use crate::{autofix, docstrings, noqa, visibility};
const GLOBAL_SCOPE_INDEX: usize = 0;

type DeferralContext<'a> = (Vec<usize>, Vec<RefEquality<'a, Stmt>>);
type AnnotationContext = (bool, bool);

#[allow(clippy::struct_excessive_bools)]
pub struct Checker<'a> {
Expand Down Expand Up @@ -84,8 +85,8 @@ pub struct Checker<'a> {
pub(crate) scopes: Vec<Scope<'a>>,
pub(crate) scope_stack: Vec<usize>,
pub(crate) dead_scopes: Vec<(usize, Vec<usize>)>,
deferred_string_type_definitions: Vec<(Range, &'a str, bool, DeferralContext<'a>)>,
deferred_type_definitions: Vec<(&'a Expr, bool, DeferralContext<'a>)>,
deferred_string_type_definitions: Vec<(Range, &'a str, AnnotationContext, DeferralContext<'a>)>,
deferred_type_definitions: Vec<(&'a Expr, AnnotationContext, DeferralContext<'a>)>,
deferred_functions: Vec<(&'a Stmt, DeferralContext<'a>, VisibleScope)>,
deferred_lambdas: Vec<(&'a Expr, DeferralContext<'a>)>,
deferred_for_loops: Vec<(&'a Stmt, DeferralContext<'a>)>,
Expand Down Expand Up @@ -2065,13 +2066,13 @@ where
self.deferred_string_type_definitions.push((
Range::from_located(expr),
value,
self.in_annotation,
(self.in_annotation, self.in_type_checking_block),
(self.scope_stack.clone(), self.parents.clone()),
));
} else {
self.deferred_type_definitions.push((
expr,
self.in_annotation,
(self.in_annotation, self.in_type_checking_block),
(self.scope_stack.clone(), self.parents.clone()),
));
}
Expand Down Expand Up @@ -3186,7 +3187,7 @@ where
self.deferred_string_type_definitions.push((
Range::from_located(expr),
value,
self.in_annotation,
(self.in_annotation, self.in_type_checking_block),
(self.scope_stack.clone(), self.parents.clone()),
));
}
Expand Down Expand Up @@ -4491,12 +4492,13 @@ impl<'a> Checker<'a> {

fn check_deferred_type_definitions(&mut self) {
self.deferred_type_definitions.reverse();
while let Some((expr, in_annotation, (scopes, parents))) =
while let Some((expr, (in_annotation, in_type_checking_block), (scopes, parents))) =
self.deferred_type_definitions.pop()
{
self.scope_stack = scopes;
self.parents = parents;
self.in_annotation = in_annotation;
self.in_type_checking_block = in_type_checking_block;
self.in_type_definition = true;
self.in_deferred_type_definition = true;
self.visit_expr(expr);
Expand All @@ -4511,7 +4513,7 @@ impl<'a> Checker<'a> {
{
let mut stacks = vec![];
self.deferred_string_type_definitions.reverse();
while let Some((range, expression, in_annotation, context)) =
while let Some((range, expression, (in_annotation, in_type_checking_block), deferral)) =
self.deferred_string_type_definitions.pop()
{
if let Ok(mut expr) = parser::parse_expression(expression, "<filename>") {
Expand All @@ -4522,7 +4524,7 @@ impl<'a> Checker<'a> {
}
relocate_expr(&mut expr, range);
allocator.push(expr);
stacks.push((in_annotation, context));
stacks.push(((in_annotation, in_type_checking_block), deferral));
} else {
if self
.settings
Expand All @@ -4538,10 +4540,13 @@ impl<'a> Checker<'a> {
}
}
}
for (expr, (in_annotation, (scopes, parents))) in allocator.iter().zip(stacks) {
for (expr, ((in_annotation, in_type_checking_block), (scopes, parents))) in
allocator.iter().zip(stacks)
{
self.scope_stack = scopes;
self.parents = parents;
self.in_annotation = in_annotation;
self.in_type_checking_block = in_type_checking_block;
self.in_type_definition = true;
self.in_deferred_string_type_definition = true;
self.visit_expr(expr);
Expand Down
1 change: 1 addition & 0 deletions crates/ruff/src/rules/flake8_type_checking/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ mod tests {
#[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_10.py"); "TCH004_10")]
#[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_11.py"); "TCH004_11")]
#[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_12.py"); "TCH004_12")]
#[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_13.py"); "TCH004_13")]
#[test_case(Rule::EmptyTypeCheckingBlock, Path::new("TCH005.py"); "TCH005")]
#[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("strict.py"); "strict")]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
expression: diagnostics
---
[]

0 comments on commit aeae63b

Please sign in to comment.