mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-10 10:22:14 +00:00
Add a ScopeKind
for the __class__
cell (#20048)
Summary -- This PR aims to resolve (or help to resolve) #18442 and #19357 by encoding the CPython semantics around the `__class__` cell in our semantic model. Namely, > `__class__` is an implicit closure reference created by the compiler if any methods in a class body refer to either `__class__` or super. from the Python [docs](https://docs.python.org/3/reference/datamodel.html#creating-the-class-object). As noted in the variant docs by @AlexWaygood, we don't fully model this behavior, opting always to create the `__class__` cell binding in a new `ScopeKind::DunderClassCell` around each method definition, without checking if any method in the class body actually refers to `__class__` or `super`. As such, this PR fixes #18442 but not #19357. Test Plan -- Existing tests, plus the tests from #19783, which now pass without any rule-specific code. Note that we opted not to alter the behavior of F841 here because flagging `__class__` in these cases still seems helpful. See the discussion in https://github.com/astral-sh/ruff/pull/20048#discussion_r2296252395 and in the test comments for more information. --------- Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com> Co-authored-by: Mikko Leppänen <mleppan23@gmail.com>
This commit is contained in:
parent
911d5cc973
commit
bc7274d148
11 changed files with 287 additions and 37 deletions
|
@ -446,7 +446,7 @@ impl Ranged for Binding<'_> {
|
|||
/// ID uniquely identifying a [Binding] in a program.
|
||||
///
|
||||
/// Using a `u32` to identify [Binding]s should be sufficient because Ruff only supports documents with a
|
||||
/// size smaller than or equal to `u32::max`. A document with the size of `u32::max` must have fewer than `u32::max`
|
||||
/// size smaller than or equal to `u32::MAX`. A document with the size of `u32::MAX` must have fewer than `u32::MAX`
|
||||
/// bindings because bindings must be separated by whitespace (and have an assignment).
|
||||
#[newtype_index]
|
||||
pub struct BindingId;
|
||||
|
@ -672,6 +672,24 @@ pub enum BindingKind<'a> {
|
|||
/// Stores the ID of the binding that was shadowed in the enclosing
|
||||
/// scope, if any.
|
||||
UnboundException(Option<BindingId>),
|
||||
|
||||
/// A binding to `__class__` in the implicit closure created around every method in a class
|
||||
/// body, if any method refers to either `__class__` or `super`.
|
||||
///
|
||||
/// ```python
|
||||
/// class C:
|
||||
/// __class__ # NameError: name '__class__' is not defined
|
||||
///
|
||||
/// def f():
|
||||
/// print(__class__) # allowed
|
||||
///
|
||||
/// def g():
|
||||
/// nonlocal __class__ # also allowed because the scope is *not* the function scope
|
||||
/// ```
|
||||
///
|
||||
/// See <https://docs.python.org/3/reference/datamodel.html#creating-the-class-object> for more
|
||||
/// details.
|
||||
DunderClassCell,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue