mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-07 21:25:08 +00:00
Recognize all symbols named TYPE_CHECKING
for in_type_checking_block
(#15719)
Closes #15681 ## Summary This changes `analyze::typing::is_type_checking_block` to recognize all symbols named "TYPE_CHECKING". This matches the current behavior of mypy and pyright as well as `flake8-type-checking`. It also drops support for detecting `if False:` and `if 0:` as type checking blocks. This used to be an option for providing backwards compatibility with Python versions that did not have a `typing` module, but has since been removed from the typing spec and is no longer supported by any of the mainstream type checkers. ## Test Plan `cargo nextest run` --------- Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
parent
81059d05fc
commit
8fcac0ff36
8 changed files with 192 additions and 15 deletions
|
@ -382,6 +382,22 @@ pub fn is_mutable_expr(expr: &Expr, semantic: &SemanticModel) -> bool {
|
|||
pub fn is_type_checking_block(stmt: &ast::StmtIf, semantic: &SemanticModel) -> bool {
|
||||
let ast::StmtIf { test, .. } = stmt;
|
||||
|
||||
if semantic.use_new_type_checking_block_detection_semantics() {
|
||||
return match test.as_ref() {
|
||||
// As long as the symbol's name is "TYPE_CHECKING" we will treat it like `typing.TYPE_CHECKING`
|
||||
// for this specific check even if it's defined somewhere else, like the current module.
|
||||
// Ex) `if TYPE_CHECKING:`
|
||||
Expr::Name(ast::ExprName { id, .. }) => {
|
||||
id == "TYPE_CHECKING"
|
||||
// Ex) `if TC:` with `from typing import TYPE_CHECKING as TC`
|
||||
|| semantic.match_typing_expr(test, "TYPE_CHECKING")
|
||||
}
|
||||
// Ex) `if typing.TYPE_CHECKING:`
|
||||
Expr::Attribute(ast::ExprAttribute { attr, .. }) => attr == "TYPE_CHECKING",
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
// Ex) `if False:`
|
||||
if is_const_false(test) {
|
||||
return true;
|
||||
|
|
|
@ -2014,6 +2014,18 @@ impl<'a> SemanticModel<'a> {
|
|||
.intersects(SemanticModelFlags::DEFERRED_CLASS_BASE)
|
||||
}
|
||||
|
||||
/// Return `true` if we should use the new semantics to recognize
|
||||
/// type checking blocks. Previously we only recognized type checking
|
||||
/// blocks if `TYPE_CHECKING` was imported from a typing module.
|
||||
///
|
||||
/// With this feature flag enabled we recognize any symbol named
|
||||
/// `TYPE_CHECKING`, regardless of where it comes from to mirror
|
||||
/// what mypy and pyright do.
|
||||
pub const fn use_new_type_checking_block_detection_semantics(&self) -> bool {
|
||||
self.flags
|
||||
.intersects(SemanticModelFlags::NEW_TYPE_CHECKING_BLOCK_DETECTION)
|
||||
}
|
||||
|
||||
/// Return an iterator over all bindings shadowed by the given [`BindingId`], within the
|
||||
/// containing scope, and across scopes.
|
||||
pub fn shadowed_bindings(
|
||||
|
@ -2545,6 +2557,14 @@ bitflags! {
|
|||
/// [#13824]: https://github.com/astral-sh/ruff/issues/13824
|
||||
const NO_TYPE_CHECK = 1 << 30;
|
||||
|
||||
/// The model special-cases any symbol named `TYPE_CHECKING`.
|
||||
///
|
||||
/// Previously we only recognized `TYPE_CHECKING` if it was part of
|
||||
/// one of the configured `typing` modules. This flag exists to
|
||||
/// test out the semantic change only in preview. This flag will go
|
||||
/// away once this change has been stabilized.
|
||||
const NEW_TYPE_CHECKING_BLOCK_DETECTION = 1 << 31;
|
||||
|
||||
/// The context is in any type annotation.
|
||||
const ANNOTATION = Self::TYPING_ONLY_ANNOTATION.bits() | Self::RUNTIME_EVALUATED_ANNOTATION.bits() | Self::RUNTIME_REQUIRED_ANNOTATION.bits();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue