mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 13:24:57 +00:00
[ty] Treat __new__
as a static method (#20212)
## Summary Pull this out of https://github.com/astral-sh/ruff/pull/18473 as an isolated change to make sure it has no adverse effects. The wrong behavior is observable on `main` for something like ```py class C: def __new__(cls) -> "C": cls.x = 1 C.x # previously: Attribute `x` can only be accessed on instances # now: Type `<class 'C'>` has no attribute `x` ``` where we currently treat `x` as an *instance* attribute (because we consider `__new__` to be a normal function and `cls` to be the "self" attribute). With this PR, we do not consider `x` to be an attribute, neither on the class nor on instances of `C`. If this turns out to be an important feature, we should add it intentionally, instead of accidentally. ## Test Plan Ecosystem checks.
This commit is contained in:
parent
cb1ba0d4c2
commit
0d4f7dde99
3 changed files with 10 additions and 10 deletions
|
@ -290,8 +290,7 @@ impl<'db> Bindings<'db> {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
} else if function.has_known_decorator(db, FunctionDecorators::STATICMETHOD)
|
||||
{
|
||||
} else if function.is_staticmethod(db) {
|
||||
overload.set_return_type(Type::FunctionLiteral(function));
|
||||
} else if let [Some(first), _] = overload.parameter_types() {
|
||||
if first.is_none(db) {
|
||||
|
|
|
@ -3,10 +3,8 @@ use std::sync::{LazyLock, Mutex};
|
|||
use super::TypeVarVariance;
|
||||
use super::{
|
||||
BoundTypeVarInstance, IntersectionBuilder, MemberLookupPolicy, Mro, MroError, MroIterator,
|
||||
SpecialFormType, SubclassOfType, Truthiness, Type, TypeQualifiers,
|
||||
class_base::ClassBase,
|
||||
function::{FunctionDecorators, FunctionType},
|
||||
infer_expression_type, infer_unpack_types,
|
||||
SpecialFormType, SubclassOfType, Truthiness, Type, TypeQualifiers, class_base::ClassBase,
|
||||
function::FunctionType, infer_expression_type, infer_unpack_types,
|
||||
};
|
||||
use crate::FxOrderMap;
|
||||
use crate::module_resolver::KnownModule;
|
||||
|
@ -1257,10 +1255,7 @@ pub(super) enum MethodDecorator {
|
|||
|
||||
impl MethodDecorator {
|
||||
fn try_from_fn_type(db: &dyn Db, fn_type: FunctionType) -> Result<Self, ()> {
|
||||
match (
|
||||
fn_type.is_classmethod(db),
|
||||
fn_type.has_known_decorator(db, FunctionDecorators::STATICMETHOD),
|
||||
) {
|
||||
match (fn_type.is_classmethod(db), fn_type.is_staticmethod(db)) {
|
||||
(true, true) => Err(()), // A method can't be static and class method at the same time.
|
||||
(true, false) => Ok(Self::ClassMethod),
|
||||
(false, true) => Ok(Self::StaticMethod),
|
||||
|
|
|
@ -731,6 +731,12 @@ impl<'db> FunctionType<'db> {
|
|||
)
|
||||
}
|
||||
|
||||
/// Returns true if this method is decorated with `@staticmethod`, or if it is implicitly a
|
||||
/// static method.
|
||||
pub(crate) fn is_staticmethod(self, db: &'db dyn Db) -> bool {
|
||||
self.has_known_decorator(db, FunctionDecorators::STATICMETHOD) || self.name(db) == "__new__"
|
||||
}
|
||||
|
||||
/// If the implementation of this function is deprecated, returns the `@warnings.deprecated`.
|
||||
///
|
||||
/// Checking if an overload is deprecated requires deeper call analysis.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue