[red-knot] respect TYPE_CHECKING even if not imported from typing (#16468)
## Summary This PR closes #15722. The change is that if the variable `TYPE_CHECKING` is defined/imported, the type of the variable is interpreted as `Literal[True]` regardless of what the value is. This is compatible with the behavior of other type checkers (e.g. mypy, pyright). ## Test Plan I ran the tests with `cargo test -p red_knot_python_semantic` and confirmed that all tests passed. --------- Co-authored-by: Carl Meyer <carl@astral.sh>
This commit is contained in:
committed by
GitHub
parent
c9ab925275
commit
1977dda079
@@ -458,8 +458,12 @@ fn symbol_by_id<'db>(
|
||||
// a diagnostic if we see it being modified externally. In type inference, we
|
||||
// can assign a "narrow" type to it even if it is not *declared*. This means, we
|
||||
// do not have to call [`widen_type_for_undeclared_public_symbol`].
|
||||
let is_considered_non_modifiable =
|
||||
symbol_table(db, scope).symbol(symbol_id).name() == "__slots__";
|
||||
// `TYPE_CHECKING` is a special variable that should only be assigned `False`
|
||||
// at runtime, but is always considered `True` in type checking.
|
||||
// See mdtest/known_constants.md#user-defined-type_checking for details.
|
||||
let is_considered_non_modifiable = symbol_table(db, scope).symbol(symbol_id).name()
|
||||
== "__slots__"
|
||||
|| symbol_table(db, scope).symbol(symbol_id).name() == "TYPE_CHECKING";
|
||||
|
||||
widen_type_for_undeclared_public_symbol(db, inferred, is_considered_non_modifiable)
|
||||
.into()
|
||||
|
||||
@@ -2149,7 +2149,12 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||
unpacked.expression_type(name_ast_id)
|
||||
}
|
||||
TargetKind::Name => {
|
||||
if self.in_stub() && value.is_ellipsis_literal_expr() {
|
||||
// `TYPE_CHECKING` is a special variable that should only be assigned `False`
|
||||
// at runtime, but is always considered `True` in type checking.
|
||||
// See mdtest/known_constants.md#user-defined-type_checking for details.
|
||||
if &name.id == "TYPE_CHECKING" {
|
||||
Type::BooleanLiteral(true)
|
||||
} else if self.in_stub() && value.is_ellipsis_literal_expr() {
|
||||
Type::unknown()
|
||||
} else {
|
||||
value_ty
|
||||
|
||||
Reference in New Issue
Block a user