[ty] "foo".startswith is not an instance of types.MethodWrapperType (#20317)

This commit is contained in:
Alex Waygood 2025-09-10 12:14:26 +01:00 committed by GitHub
parent fd7eb1e22f
commit b85c995927
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 236 additions and 151 deletions

View file

@ -2057,8 +2057,13 @@ reveal_type(f.__kwdefaults__) # revealed: dict[str, Any] | None
Some attributes are special-cased, however:
```py
import types
from ty_extensions import static_assert, TypeOf, is_subtype_of
reveal_type(f.__get__) # revealed: <method-wrapper `__get__` of `f`>
reveal_type(f.__call__) # revealed: <method-wrapper `__call__` of `f`>
static_assert(is_subtype_of(TypeOf[f.__get__], types.MethodWrapperType))
static_assert(is_subtype_of(TypeOf[f.__call__], types.MethodWrapperType))
```
### Int-literal attributes

View file

@ -47,4 +47,19 @@ def _(string_instance: str, literalstring: LiteralString):
reveal_type("a".startswith(literalstring)) # revealed: bool
```
Unlike bound methods for some other classes implemented in C, `"foo".startswith` is an instance of
`types.BuiltinFunctionType` at runtime, rather than `types.MethodWrapperType`:
```py
import types
from ty_extensions import TypeOf, static_assert, is_subtype_of
static_assert(is_subtype_of(TypeOf["foo".startswith], types.BuiltinFunctionType))
# `types.BuiltinMethodType` is just an alias for `types.BuiltinFunctionType`
static_assert(is_subtype_of(TypeOf["foo".startswith], types.BuiltinMethodType))
static_assert(not is_subtype_of(TypeOf["foo".startswith], types.MethodWrapperType))
static_assert(not is_subtype_of(TypeOf["foo".startswith], types.WrapperDescriptorType))
```
[`sys.platform` checks]: https://docs.python.org/3/library/sys.html#sys.platform

View file

@ -585,13 +585,16 @@ that method calls work as expected. See [this test suite](./call/methods.md) for
Here, we only demonstrate how `__get__` works on functions:
```py
import types
from inspect import getattr_static
from ty_extensions import static_assert, is_subtype_of, TypeOf
def f(x: object) -> str:
return "a"
reveal_type(f) # revealed: def f(x: object) -> str
reveal_type(f.__get__) # revealed: <method-wrapper `__get__` of `f`>
static_assert(is_subtype_of(TypeOf[f.__get__], types.MethodWrapperType))
reveal_type(f.__get__(None, type(f))) # revealed: def f(x: object) -> str
reveal_type(f.__get__(None, type(f))(1)) # revealed: str
@ -599,6 +602,7 @@ wrapper_descriptor = getattr_static(f, "__get__")
reveal_type(wrapper_descriptor) # revealed: <wrapper-descriptor `__get__` of `function` objects>
reveal_type(wrapper_descriptor(f, None, type(f))) # revealed: def f(x: object) -> str
static_assert(is_subtype_of(TypeOf[wrapper_descriptor], types.WrapperDescriptorType))
# Attribute access on the method-wrapper `f.__get__` falls back to `MethodWrapperType`:
reveal_type(f.__get__.__hash__) # revealed: bound method MethodWrapperType.__hash__() -> int

View file

@ -303,3 +303,18 @@ reveal_type(attr_property.fset(c, "a")) # revealed: None
# error: [invalid-argument-type]
attr_property.fset(c, 1)
```
At runtime, `attr_property.__get__` and `attr_property.__set__` are both instances of
`types.MethodWrapperType`:
```py
import types
from ty_extensions import TypeOf, static_assert, is_subtype_of
static_assert(is_subtype_of(TypeOf[attr_property.__get__], types.MethodWrapperType))
static_assert(is_subtype_of(TypeOf[attr_property.__set__], types.MethodWrapperType))
static_assert(not is_subtype_of(TypeOf[attr_property.__get__], types.WrapperDescriptorType))
static_assert(not is_subtype_of(TypeOf[attr_property.__set__], types.WrapperDescriptorType))
static_assert(not is_subtype_of(TypeOf[attr_property.__get__], types.BuiltinMethodType))
static_assert(not is_subtype_of(TypeOf[attr_property.__set__], types.BuiltinMethodType))
```

View file

@ -326,7 +326,7 @@ impl<'db> Completion<'db> {
| Type::WrapperDescriptor(_)
| Type::DataclassTransformer(_)
| Type::Callable(_) => CompletionKind::Function,
Type::BoundMethod(_) | Type::MethodWrapper(_) => CompletionKind::Method,
Type::BoundMethod(_) | Type::KnownBoundMethod(_) => CompletionKind::Method,
Type::ModuleLiteral(_) => CompletionKind::Module,
Type::ClassLiteral(_) | Type::GenericAlias(_) | Type::SubclassOf(_) => {
CompletionKind::Class

View file

@ -618,22 +618,21 @@ pub enum Type<'db> {
/// the `self` parameter, and return a `MethodType & Callable[[int], str]`.
/// One drawback would be that we could not show the bound instance when that type is displayed.
BoundMethod(BoundMethodType<'db>),
/// Represents a specific instance of `types.MethodWrapperType`.
/// Represents a specific instance of a bound method type for a builtin class.
///
/// TODO: consider replacing this with `Callable & types.MethodWrapperType` type?
/// Requires `Callable` to be able to represent overloads, e.g. `types.FunctionType.__get__` has
/// The `Callable` type would need to be overloaded -- e.g. `types.FunctionType.__get__` has
/// this behaviour when a method is accessed on a class vs an instance:
///
/// ```txt
/// * (None, type) -> Literal[function_on_which_it_was_called]
/// * (object, type | None) -> BoundMethod[instance, function_on_which_it_was_called]
/// ```
MethodWrapper(MethodWrapperKind<'db>),
KnownBoundMethod(KnownBoundMethodType<'db>),
/// Represents a specific instance of `types.WrapperDescriptorType`.
///
/// TODO: Similar to above, this could eventually be replaced by a generic `Callable`
/// type. We currently add this as a separate variant because `FunctionType.__get__`
/// is an overloaded method and we do not support `@overload` yet.
/// type.
WrapperDescriptor(WrapperDescriptorKind),
/// A special callable that is returned by a `dataclass(…)` call. It is usually
/// used as a decorator. Note that this is only used as a return type for actual
@ -1121,8 +1120,8 @@ impl<'db> Type<'db> {
Type::PropertyInstance(property) => visitor.visit(self, || {
Type::PropertyInstance(property.normalized_impl(db, visitor))
}),
Type::MethodWrapper(method_kind) => visitor.visit(self, || {
Type::MethodWrapper(method_kind.normalized_impl(db, visitor))
Type::KnownBoundMethod(method_kind) => visitor.visit(self, || {
Type::KnownBoundMethod(method_kind.normalized_impl(db, visitor))
}),
Type::BoundMethod(method) => visitor.visit(self, || {
Type::BoundMethod(method.normalized_impl(db, visitor))
@ -1192,7 +1191,7 @@ impl<'db> Type<'db> {
| Type::FunctionLiteral(..)
| Type::BoundMethod(_)
| Type::WrapperDescriptor(_)
| Type::MethodWrapper(_)
| Type::KnownBoundMethod(_)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
| Type::ModuleLiteral(..)
@ -1291,7 +1290,7 @@ impl<'db> Type<'db> {
| Type::TypedDict(_) => None,
// TODO
Type::MethodWrapper(_)
Type::KnownBoundMethod(_)
| Type::WrapperDescriptor(_)
| Type::DataclassDecorator(_)
| Type::ModuleLiteral(_)
@ -1580,7 +1579,7 @@ impl<'db> Type<'db> {
(Type::BoundMethod(self_method), Type::BoundMethod(target_method)) => {
self_method.has_relation_to_impl(db, target_method, relation, visitor)
}
(Type::MethodWrapper(self_method), Type::MethodWrapper(target_method)) => {
(Type::KnownBoundMethod(self_method), Type::KnownBoundMethod(target_method)) => {
self_method.has_relation_to_impl(db, target_method, relation, visitor)
}
@ -1662,7 +1661,8 @@ impl<'db> Type<'db> {
(Type::BoundMethod(_), _) => KnownClass::MethodType
.to_instance(db)
.has_relation_to_impl(db, target, relation, visitor),
(Type::MethodWrapper(_), _) => KnownClass::WrapperDescriptorType
(Type::KnownBoundMethod(method), _) => method
.class()
.to_instance(db)
.has_relation_to_impl(db, target, relation, visitor),
(Type::WrapperDescriptor(_), _) => KnownClass::WrapperDescriptorType
@ -1901,7 +1901,7 @@ impl<'db> Type<'db> {
(Type::BoundMethod(self_method), Type::BoundMethod(target_method)) => {
self_method.is_equivalent_to_impl(db, target_method, visitor)
}
(Type::MethodWrapper(self_method), Type::MethodWrapper(target_method)) => {
(Type::KnownBoundMethod(self_method), Type::KnownBoundMethod(target_method)) => {
self_method.is_equivalent_to_impl(db, target_method, visitor)
}
(Type::Callable(first), Type::Callable(second)) => {
@ -2074,7 +2074,7 @@ impl<'db> Type<'db> {
| Type::EnumLiteral(..)
| Type::FunctionLiteral(..)
| Type::BoundMethod(..)
| Type::MethodWrapper(..)
| Type::KnownBoundMethod(..)
| Type::WrapperDescriptor(..)
| Type::ModuleLiteral(..)
| Type::ClassLiteral(..)
@ -2088,7 +2088,7 @@ impl<'db> Type<'db> {
| Type::EnumLiteral(..)
| Type::FunctionLiteral(..)
| Type::BoundMethod(..)
| Type::MethodWrapper(..)
| Type::KnownBoundMethod(..)
| Type::WrapperDescriptor(..)
| Type::ModuleLiteral(..)
| Type::ClassLiteral(..)
@ -2107,7 +2107,7 @@ impl<'db> Type<'db> {
| Type::EnumLiteral(..)
| Type::FunctionLiteral(..)
| Type::BoundMethod(..)
| Type::MethodWrapper(..)
| Type::KnownBoundMethod(..)
| Type::WrapperDescriptor(..)
| Type::ModuleLiteral(..),
)
@ -2120,7 +2120,7 @@ impl<'db> Type<'db> {
| Type::EnumLiteral(..)
| Type::FunctionLiteral(..)
| Type::BoundMethod(..)
| Type::MethodWrapper(..)
| Type::KnownBoundMethod(..)
| Type::WrapperDescriptor(..)
| Type::ModuleLiteral(..),
Type::SubclassOf(_),
@ -2374,8 +2374,9 @@ impl<'db> Type<'db> {
.to_instance(db)
.is_disjoint_from_impl(db, other, visitor),
(Type::MethodWrapper(_), other) | (other, Type::MethodWrapper(_)) => {
KnownClass::MethodWrapperType
(Type::KnownBoundMethod(method), other) | (other, Type::KnownBoundMethod(method)) => {
method
.class()
.to_instance(db)
.is_disjoint_from_impl(db, other, visitor)
}
@ -2562,7 +2563,7 @@ impl<'db> Type<'db> {
// ```
false
}
Type::MethodWrapper(_) => {
Type::KnownBoundMethod(_) => {
// Just a special case of `BoundMethod` really
// (this variant represents `f.__get__`, where `f` is any function)
false
@ -2599,7 +2600,7 @@ impl<'db> Type<'db> {
Type::FunctionLiteral(..)
| Type::BoundMethod(_)
| Type::WrapperDescriptor(_)
| Type::MethodWrapper(_)
| Type::KnownBoundMethod(_)
| Type::ModuleLiteral(..)
| Type::ClassLiteral(..)
| Type::GenericAlias(..)
@ -2788,7 +2789,7 @@ impl<'db> Type<'db> {
| Type::Callable(_)
| Type::BoundMethod(_)
| Type::WrapperDescriptor(_)
| Type::MethodWrapper(_)
| Type::KnownBoundMethod(_)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
| Type::ModuleLiteral(_)
@ -2900,9 +2901,9 @@ impl<'db> Type<'db> {
Type::BoundMethod(_) => KnownClass::MethodType
.to_instance(db)
.instance_member(db, name),
Type::MethodWrapper(_) => KnownClass::MethodWrapperType
.to_instance(db)
.instance_member(db, name),
Type::KnownBoundMethod(method) => {
method.class().to_instance(db).instance_member(db, name)
}
Type::WrapperDescriptor(_) => KnownClass::WrapperDescriptorType
.to_instance(db)
.instance_member(db, name),
@ -3326,23 +3327,23 @@ impl<'db> Type<'db> {
Type::Dynamic(..) | Type::Never => Place::bound(self).into(),
Type::FunctionLiteral(function) if name == "__get__" => Place::bound(
Type::MethodWrapper(MethodWrapperKind::FunctionTypeDunderGet(function)),
Type::KnownBoundMethod(KnownBoundMethodType::FunctionTypeDunderGet(function)),
)
.into(),
Type::FunctionLiteral(function) if name == "__call__" => Place::bound(
Type::MethodWrapper(MethodWrapperKind::FunctionTypeDunderCall(function)),
Type::KnownBoundMethod(KnownBoundMethodType::FunctionTypeDunderCall(function)),
)
.into(),
Type::PropertyInstance(property) if name == "__get__" => Place::bound(
Type::MethodWrapper(MethodWrapperKind::PropertyDunderGet(property)),
Type::KnownBoundMethod(KnownBoundMethodType::PropertyDunderGet(property)),
)
.into(),
Type::PropertyInstance(property) if name == "__set__" => Place::bound(
Type::MethodWrapper(MethodWrapperKind::PropertyDunderSet(property)),
Type::KnownBoundMethod(KnownBoundMethodType::PropertyDunderSet(property)),
)
.into(),
Type::StringLiteral(literal) if name == "startswith" => Place::bound(
Type::MethodWrapper(MethodWrapperKind::StrStartswith(literal)),
Type::KnownBoundMethod(KnownBoundMethodType::StrStartswith(literal)),
)
.into(),
@ -3385,7 +3386,8 @@ impl<'db> Type<'db> {
})
}
},
Type::MethodWrapper(_) => KnownClass::MethodWrapperType
Type::KnownBoundMethod(method) => method
.class()
.to_instance(db)
.member_lookup_with_policy(db, name, policy),
Type::WrapperDescriptor(_) => KnownClass::WrapperDescriptorType
@ -3786,7 +3788,7 @@ impl<'db> Type<'db> {
Type::FunctionLiteral(_)
| Type::BoundMethod(_)
| Type::WrapperDescriptor(_)
| Type::MethodWrapper(_)
| Type::KnownBoundMethod(_)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
| Type::ModuleLiteral(_)
@ -3949,9 +3951,9 @@ impl<'db> Type<'db> {
.into()
}
Type::MethodWrapper(
MethodWrapperKind::FunctionTypeDunderGet(_)
| MethodWrapperKind::PropertyDunderGet(_),
Type::KnownBoundMethod(
KnownBoundMethodType::FunctionTypeDunderGet(_)
| KnownBoundMethodType::PropertyDunderGet(_),
) => {
// Here, we dynamically model the overloaded function signature of `types.FunctionType.__get__`.
// This is required because we need to return more precise types than what the signature in
@ -4055,7 +4057,7 @@ impl<'db> Type<'db> {
.into()
}
Type::MethodWrapper(MethodWrapperKind::PropertyDunderSet(_)) => Binding::single(
Type::KnownBoundMethod(KnownBoundMethodType::PropertyDunderSet(_)) => Binding::single(
self,
Signature::new(
Parameters::new([
@ -4085,7 +4087,7 @@ impl<'db> Type<'db> {
)
.into(),
Type::MethodWrapper(MethodWrapperKind::StrStartswith(_)) => Binding::single(
Type::KnownBoundMethod(KnownBoundMethodType::StrStartswith(_)) => Binding::single(
self,
Signature::new(
Parameters::new([
@ -4814,7 +4816,7 @@ impl<'db> Type<'db> {
}
// TODO: these are actually callable
Type::MethodWrapper(_) | Type::DataclassDecorator(_) => {
Type::KnownBoundMethod(_) | Type::DataclassDecorator(_) => {
CallableBinding::not_callable(self).into()
}
@ -5065,7 +5067,7 @@ impl<'db> Type<'db> {
Type::FunctionLiteral(_)
| Type::GenericAlias(_)
| Type::BoundMethod(_)
| Type::MethodWrapper(_)
| Type::KnownBoundMethod(_)
| Type::WrapperDescriptor(_)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
@ -5527,7 +5529,7 @@ impl<'db> Type<'db> {
| Type::EnumLiteral(_)
| Type::FunctionLiteral(_)
| Type::Callable(..)
| Type::MethodWrapper(_)
| Type::KnownBoundMethod(_)
| Type::BoundMethod(_)
| Type::WrapperDescriptor(_)
| Type::DataclassDecorator(_)
@ -5607,7 +5609,7 @@ impl<'db> Type<'db> {
| Type::Callable(_)
| Type::BoundMethod(_)
| Type::WrapperDescriptor(_)
| Type::MethodWrapper(_)
| Type::KnownBoundMethod(_)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
| Type::Never
@ -5896,7 +5898,7 @@ impl<'db> Type<'db> {
Type::EnumLiteral(enum_literal) => Type::ClassLiteral(enum_literal.enum_class(db)),
Type::FunctionLiteral(_) => KnownClass::FunctionType.to_class_literal(db),
Type::BoundMethod(_) => KnownClass::MethodType.to_class_literal(db),
Type::MethodWrapper(_) => KnownClass::MethodWrapperType.to_class_literal(db),
Type::KnownBoundMethod(method) => method.class().to_class_literal(db),
Type::WrapperDescriptor(_) => KnownClass::WrapperDescriptorType.to_class_literal(db),
Type::DataclassDecorator(_) => KnownClass::FunctionType.to_class_literal(db),
Type::Callable(callable) if callable.is_function_like(db) => {
@ -6095,26 +6097,26 @@ impl<'db> Type<'db> {
Type::ProtocolInstance(instance.apply_type_mapping_impl(db, type_mapping, visitor))
}
Type::MethodWrapper(MethodWrapperKind::FunctionTypeDunderGet(function)) => {
Type::MethodWrapper(MethodWrapperKind::FunctionTypeDunderGet(
Type::KnownBoundMethod(KnownBoundMethodType::FunctionTypeDunderGet(function)) => {
Type::KnownBoundMethod(KnownBoundMethodType::FunctionTypeDunderGet(
function.with_type_mapping(db, type_mapping),
))
}
Type::MethodWrapper(MethodWrapperKind::FunctionTypeDunderCall(function)) => {
Type::MethodWrapper(MethodWrapperKind::FunctionTypeDunderCall(
Type::KnownBoundMethod(KnownBoundMethodType::FunctionTypeDunderCall(function)) => {
Type::KnownBoundMethod(KnownBoundMethodType::FunctionTypeDunderCall(
function.with_type_mapping(db, type_mapping),
))
}
Type::MethodWrapper(MethodWrapperKind::PropertyDunderGet(property)) => {
Type::MethodWrapper(MethodWrapperKind::PropertyDunderGet(
Type::KnownBoundMethod(KnownBoundMethodType::PropertyDunderGet(property)) => {
Type::KnownBoundMethod(KnownBoundMethodType::PropertyDunderGet(
property.apply_type_mapping_impl(db, type_mapping, visitor),
))
}
Type::MethodWrapper(MethodWrapperKind::PropertyDunderSet(property)) => {
Type::MethodWrapper(MethodWrapperKind::PropertyDunderSet(
Type::KnownBoundMethod(KnownBoundMethodType::PropertyDunderSet(property)) => {
Type::KnownBoundMethod(KnownBoundMethodType::PropertyDunderSet(
property.apply_type_mapping_impl(db, type_mapping, visitor),
))
}
@ -6198,7 +6200,7 @@ impl<'db> Type<'db> {
| Type::AlwaysTruthy
| Type::AlwaysFalsy
| Type::WrapperDescriptor(_)
| Type::MethodWrapper(MethodWrapperKind::StrStartswith(_))
| Type::KnownBoundMethod(KnownBoundMethodType::StrStartswith(_))
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
// A non-generic class never needs to be specialized. A generic class is specialized
@ -6266,16 +6268,16 @@ impl<'db> Type<'db> {
);
}
Type::MethodWrapper(
MethodWrapperKind::FunctionTypeDunderGet(function)
| MethodWrapperKind::FunctionTypeDunderCall(function),
Type::KnownBoundMethod(
KnownBoundMethodType::FunctionTypeDunderGet(function)
| KnownBoundMethodType::FunctionTypeDunderCall(function),
) => {
function.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}
Type::MethodWrapper(
MethodWrapperKind::PropertyDunderGet(property)
| MethodWrapperKind::PropertyDunderSet(property),
Type::KnownBoundMethod(
KnownBoundMethodType::PropertyDunderGet(property)
| KnownBoundMethodType::PropertyDunderSet(property),
) => {
property.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}
@ -6343,7 +6345,7 @@ impl<'db> Type<'db> {
| Type::AlwaysTruthy
| Type::AlwaysFalsy
| Type::WrapperDescriptor(_)
| Type::MethodWrapper(MethodWrapperKind::StrStartswith(_))
| Type::KnownBoundMethod(KnownBoundMethodType::StrStartswith(_))
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
| Type::ModuleLiteral(_)
@ -6459,7 +6461,7 @@ impl<'db> Type<'db> {
| Self::BytesLiteral(_)
// TODO: For enum literals, it would be even better to jump to the definition of the specific member
| Self::EnumLiteral(_)
| Self::MethodWrapper(_)
| Self::KnownBoundMethod(_)
| Self::WrapperDescriptor(_)
| Self::DataclassDecorator(_)
| Self::DataclassTransformer(_)
@ -6645,7 +6647,7 @@ impl<'db> VarianceInferable<'db> for Type<'db> {
Type::Dynamic(_)
| Type::Never
| Type::WrapperDescriptor(_)
| Type::MethodWrapper(_)
| Type::KnownBoundMethod(_)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
| Type::ModuleLiteral(_)
@ -9153,11 +9155,14 @@ impl<'db> CallableType<'db> {
}
}
/// Represents a specific instance of `types.MethodWrapperType`
/// Represents a specific instance of a bound method type for a builtin class.
///
/// Unlike bound methods of user-defined classes, these are not generally instances
/// of `types.BoundMethodType` at runtime.
#[derive(
Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, salsa::Update, get_size2::GetSize,
)]
pub enum MethodWrapperKind<'db> {
pub enum KnownBoundMethodType<'db> {
/// Method wrapper for `some_function.__get__`
FunctionTypeDunderGet(FunctionType<'db>),
/// Method wrapper for `some_function.__call__`
@ -9176,29 +9181,29 @@ pub enum MethodWrapperKind<'db> {
pub(super) fn walk_method_wrapper_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
db: &'db dyn Db,
method_wrapper: MethodWrapperKind<'db>,
method_wrapper: KnownBoundMethodType<'db>,
visitor: &V,
) {
match method_wrapper {
MethodWrapperKind::FunctionTypeDunderGet(function) => {
KnownBoundMethodType::FunctionTypeDunderGet(function) => {
visitor.visit_function_type(db, function);
}
MethodWrapperKind::FunctionTypeDunderCall(function) => {
KnownBoundMethodType::FunctionTypeDunderCall(function) => {
visitor.visit_function_type(db, function);
}
MethodWrapperKind::PropertyDunderGet(property) => {
KnownBoundMethodType::PropertyDunderGet(property) => {
visitor.visit_property_instance_type(db, property);
}
MethodWrapperKind::PropertyDunderSet(property) => {
KnownBoundMethodType::PropertyDunderSet(property) => {
visitor.visit_property_instance_type(db, property);
}
MethodWrapperKind::StrStartswith(string_literal) => {
KnownBoundMethodType::StrStartswith(string_literal) => {
visitor.visit_type(db, Type::StringLiteral(string_literal));
}
}
}
impl<'db> MethodWrapperKind<'db> {
impl<'db> KnownBoundMethodType<'db> {
fn has_relation_to_impl<C: Constraints<'db>>(
self,
db: &'db dyn Db,
@ -9208,32 +9213,38 @@ impl<'db> MethodWrapperKind<'db> {
) -> C {
match (self, other) {
(
MethodWrapperKind::FunctionTypeDunderGet(self_function),
MethodWrapperKind::FunctionTypeDunderGet(other_function),
KnownBoundMethodType::FunctionTypeDunderGet(self_function),
KnownBoundMethodType::FunctionTypeDunderGet(other_function),
) => self_function.has_relation_to_impl(db, other_function, relation, visitor),
(
MethodWrapperKind::FunctionTypeDunderCall(self_function),
MethodWrapperKind::FunctionTypeDunderCall(other_function),
KnownBoundMethodType::FunctionTypeDunderCall(self_function),
KnownBoundMethodType::FunctionTypeDunderCall(other_function),
) => self_function.has_relation_to_impl(db, other_function, relation, visitor),
(MethodWrapperKind::PropertyDunderGet(_), MethodWrapperKind::PropertyDunderGet(_))
| (MethodWrapperKind::PropertyDunderSet(_), MethodWrapperKind::PropertyDunderSet(_))
| (MethodWrapperKind::StrStartswith(_), MethodWrapperKind::StrStartswith(_)) => {
(
KnownBoundMethodType::PropertyDunderGet(_),
KnownBoundMethodType::PropertyDunderGet(_),
)
| (
KnownBoundMethodType::PropertyDunderSet(_),
KnownBoundMethodType::PropertyDunderSet(_),
)
| (KnownBoundMethodType::StrStartswith(_), KnownBoundMethodType::StrStartswith(_)) => {
C::from_bool(db, self == other)
}
(
MethodWrapperKind::FunctionTypeDunderGet(_)
| MethodWrapperKind::FunctionTypeDunderCall(_)
| MethodWrapperKind::PropertyDunderGet(_)
| MethodWrapperKind::PropertyDunderSet(_)
| MethodWrapperKind::StrStartswith(_),
MethodWrapperKind::FunctionTypeDunderGet(_)
| MethodWrapperKind::FunctionTypeDunderCall(_)
| MethodWrapperKind::PropertyDunderGet(_)
| MethodWrapperKind::PropertyDunderSet(_)
| MethodWrapperKind::StrStartswith(_),
KnownBoundMethodType::FunctionTypeDunderGet(_)
| KnownBoundMethodType::FunctionTypeDunderCall(_)
| KnownBoundMethodType::PropertyDunderGet(_)
| KnownBoundMethodType::PropertyDunderSet(_)
| KnownBoundMethodType::StrStartswith(_),
KnownBoundMethodType::FunctionTypeDunderGet(_)
| KnownBoundMethodType::FunctionTypeDunderCall(_)
| KnownBoundMethodType::PropertyDunderGet(_)
| KnownBoundMethodType::PropertyDunderSet(_)
| KnownBoundMethodType::StrStartswith(_),
) => C::unsatisfiable(db),
}
}
@ -9246,51 +9257,68 @@ impl<'db> MethodWrapperKind<'db> {
) -> C {
match (self, other) {
(
MethodWrapperKind::FunctionTypeDunderGet(self_function),
MethodWrapperKind::FunctionTypeDunderGet(other_function),
KnownBoundMethodType::FunctionTypeDunderGet(self_function),
KnownBoundMethodType::FunctionTypeDunderGet(other_function),
) => self_function.is_equivalent_to_impl(db, other_function, visitor),
(
MethodWrapperKind::FunctionTypeDunderCall(self_function),
MethodWrapperKind::FunctionTypeDunderCall(other_function),
KnownBoundMethodType::FunctionTypeDunderCall(self_function),
KnownBoundMethodType::FunctionTypeDunderCall(other_function),
) => self_function.is_equivalent_to_impl(db, other_function, visitor),
(MethodWrapperKind::PropertyDunderGet(_), MethodWrapperKind::PropertyDunderGet(_))
| (MethodWrapperKind::PropertyDunderSet(_), MethodWrapperKind::PropertyDunderSet(_))
| (MethodWrapperKind::StrStartswith(_), MethodWrapperKind::StrStartswith(_)) => {
(
KnownBoundMethodType::PropertyDunderGet(_),
KnownBoundMethodType::PropertyDunderGet(_),
)
| (
KnownBoundMethodType::PropertyDunderSet(_),
KnownBoundMethodType::PropertyDunderSet(_),
)
| (KnownBoundMethodType::StrStartswith(_), KnownBoundMethodType::StrStartswith(_)) => {
C::from_bool(db, self == other)
}
(
MethodWrapperKind::FunctionTypeDunderGet(_)
| MethodWrapperKind::FunctionTypeDunderCall(_)
| MethodWrapperKind::PropertyDunderGet(_)
| MethodWrapperKind::PropertyDunderSet(_)
| MethodWrapperKind::StrStartswith(_),
MethodWrapperKind::FunctionTypeDunderGet(_)
| MethodWrapperKind::FunctionTypeDunderCall(_)
| MethodWrapperKind::PropertyDunderGet(_)
| MethodWrapperKind::PropertyDunderSet(_)
| MethodWrapperKind::StrStartswith(_),
KnownBoundMethodType::FunctionTypeDunderGet(_)
| KnownBoundMethodType::FunctionTypeDunderCall(_)
| KnownBoundMethodType::PropertyDunderGet(_)
| KnownBoundMethodType::PropertyDunderSet(_)
| KnownBoundMethodType::StrStartswith(_),
KnownBoundMethodType::FunctionTypeDunderGet(_)
| KnownBoundMethodType::FunctionTypeDunderCall(_)
| KnownBoundMethodType::PropertyDunderGet(_)
| KnownBoundMethodType::PropertyDunderSet(_)
| KnownBoundMethodType::StrStartswith(_),
) => C::unsatisfiable(db),
}
}
fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
match self {
MethodWrapperKind::FunctionTypeDunderGet(function) => {
MethodWrapperKind::FunctionTypeDunderGet(function.normalized_impl(db, visitor))
KnownBoundMethodType::FunctionTypeDunderGet(function) => {
KnownBoundMethodType::FunctionTypeDunderGet(function.normalized_impl(db, visitor))
}
MethodWrapperKind::FunctionTypeDunderCall(function) => {
MethodWrapperKind::FunctionTypeDunderCall(function.normalized_impl(db, visitor))
KnownBoundMethodType::FunctionTypeDunderCall(function) => {
KnownBoundMethodType::FunctionTypeDunderCall(function.normalized_impl(db, visitor))
}
MethodWrapperKind::PropertyDunderGet(property) => {
MethodWrapperKind::PropertyDunderGet(property.normalized_impl(db, visitor))
KnownBoundMethodType::PropertyDunderGet(property) => {
KnownBoundMethodType::PropertyDunderGet(property.normalized_impl(db, visitor))
}
MethodWrapperKind::PropertyDunderSet(property) => {
MethodWrapperKind::PropertyDunderSet(property.normalized_impl(db, visitor))
KnownBoundMethodType::PropertyDunderSet(property) => {
KnownBoundMethodType::PropertyDunderSet(property.normalized_impl(db, visitor))
}
MethodWrapperKind::StrStartswith(_) => self,
KnownBoundMethodType::StrStartswith(_) => self,
}
}
/// Return the [`KnownClass`] that inhabitants of this type are instances of at runtime
fn class(self) -> KnownClass {
match self {
KnownBoundMethodType::FunctionTypeDunderGet(_)
| KnownBoundMethodType::FunctionTypeDunderCall(_)
| KnownBoundMethodType::PropertyDunderGet(_)
| KnownBoundMethodType::PropertyDunderSet(_) => KnownClass::MethodWrapperType,
KnownBoundMethodType::StrStartswith(_) => KnownClass::BuiltinFunctionType,
}
}
}

View file

@ -31,9 +31,9 @@ use crate::types::generics::{Specialization, SpecializationBuilder, Specializati
use crate::types::signatures::{Parameter, ParameterForm, Parameters};
use crate::types::tuple::{Tuple, TupleLength, TupleType};
use crate::types::{
BoundMethodType, ClassLiteral, DataclassParams, FieldInstance, KnownClass, KnownInstanceType,
MethodWrapperKind, PropertyInstanceType, SpecialFormType, TypeAliasType, TypeMapping,
UnionType, WrapperDescriptorKind, enums, ide_support, todo_type,
BoundMethodType, ClassLiteral, DataclassParams, FieldInstance, KnownBoundMethodType,
KnownClass, KnownInstanceType, PropertyInstanceType, SpecialFormType, TypeAliasType,
TypeMapping, UnionType, WrapperDescriptorKind, enums, ide_support, todo_type,
};
use ruff_db::diagnostic::{Annotation, Diagnostic, SubDiagnostic, SubDiagnosticSeverity};
use ruff_python_ast::{self as ast, PythonVersion};
@ -271,7 +271,9 @@ impl<'db> Bindings<'db> {
let binding_type = binding.callable_type;
for (overload_index, overload) in binding.matching_overloads_mut() {
match binding_type {
Type::MethodWrapper(MethodWrapperKind::FunctionTypeDunderGet(function)) => {
Type::KnownBoundMethod(KnownBoundMethodType::FunctionTypeDunderGet(
function,
)) => {
if function.is_classmethod(db) {
match overload.parameter_types() {
[_, Some(owner)] => {
@ -435,7 +437,7 @@ impl<'db> Bindings<'db> {
}
}
Type::MethodWrapper(MethodWrapperKind::PropertyDunderGet(property)) => {
Type::KnownBoundMethod(KnownBoundMethodType::PropertyDunderGet(property)) => {
match overload.parameter_types() {
[Some(instance), ..] if instance.is_none(db) => {
overload.set_return_type(Type::PropertyInstance(property));
@ -488,7 +490,7 @@ impl<'db> Bindings<'db> {
}
}
Type::MethodWrapper(MethodWrapperKind::PropertyDunderSet(property)) => {
Type::KnownBoundMethod(KnownBoundMethodType::PropertyDunderSet(property)) => {
if let [Some(instance), Some(value), ..] = overload.parameter_types() {
if let Some(setter) = property.setter(db) {
if let Err(_call_error) = setter
@ -506,7 +508,7 @@ impl<'db> Bindings<'db> {
}
}
Type::MethodWrapper(MethodWrapperKind::StrStartswith(literal)) => {
Type::KnownBoundMethod(KnownBoundMethodType::StrStartswith(literal)) => {
if let [Some(Type::StringLiteral(prefix)), None, None] =
overload.parameter_types()
{
@ -1766,9 +1768,9 @@ impl<'db> CallableBinding<'db> {
FunctionKind::BoundMethod,
bound_method.function(context.db()),
)),
Type::MethodWrapper(MethodWrapperKind::FunctionTypeDunderGet(function)) => {
Some((FunctionKind::MethodWrapper, function))
}
Type::KnownBoundMethod(KnownBoundMethodType::FunctionTypeDunderGet(
function,
)) => Some((FunctionKind::MethodWrapper, function)),
_ => None,
};
@ -2730,13 +2732,13 @@ impl<'db> CallableDescription<'db> {
kind: "bound method",
name: bound_method.function(db).name(db),
}),
Type::MethodWrapper(MethodWrapperKind::FunctionTypeDunderGet(function)) => {
Type::KnownBoundMethod(KnownBoundMethodType::FunctionTypeDunderGet(function)) => {
Some(CallableDescription {
kind: "method wrapper `__get__` of function",
name: function.name(db),
})
}
Type::MethodWrapper(MethodWrapperKind::PropertyDunderGet(_)) => {
Type::KnownBoundMethod(KnownBoundMethodType::PropertyDunderGet(_)) => {
Some(CallableDescription {
kind: "method wrapper",
name: "`__get__` of property",

View file

@ -3610,6 +3610,11 @@ pub enum KnownClass {
GeneratorType,
AsyncGeneratorType,
CoroutineType,
NotImplementedType,
BuiltinFunctionType,
// Exposed as `types.EllipsisType` on Python >=3.10;
// backported as `builtins.ellipsis` by typeshed on Python <=3.9
EllipsisType,
// Typeshed
NoneType, // Part of `types` for Python >= 3.10
// Typing
@ -3637,10 +3642,6 @@ pub enum KnownClass {
OrderedDict,
// sys
VersionInfo,
// Exposed as `types.EllipsisType` on Python >=3.10;
// backported as `builtins.ellipsis` by typeshed on Python <=3.9
EllipsisType,
NotImplementedType,
// dataclasses
Field,
KwOnly,
@ -3694,6 +3695,7 @@ impl KnownClass {
| Self::AsyncGeneratorType
| Self::MethodWrapperType
| Self::CoroutineType
| Self::BuiltinFunctionType
| Self::Template => Some(Truthiness::AlwaysTrue),
Self::NoneType => Some(Truthiness::AlwaysFalse),
@ -3829,6 +3831,7 @@ impl KnownClass {
| KnownClass::NamedTupleFallback
| KnownClass::NamedTupleLike
| KnownClass::TypedDictFallback
| KnownClass::BuiltinFunctionType
| KnownClass::Template => false,
}
}
@ -3906,6 +3909,7 @@ impl KnownClass {
| KnownClass::NamedTupleFallback
| KnownClass::NamedTupleLike
| KnownClass::TypedDictFallback
| KnownClass::BuiltinFunctionType
| KnownClass::Template => false,
}
}
@ -3982,6 +3986,7 @@ impl KnownClass {
| KnownClass::TypedDictFallback
| KnownClass::NamedTupleLike
| KnownClass::NamedTupleFallback
| KnownClass::BuiltinFunctionType
| KnownClass::Template => false,
}
}
@ -4071,6 +4076,7 @@ impl KnownClass {
| Self::InitVar
| Self::NamedTupleFallback
| Self::TypedDictFallback
| Self::BuiltinFunctionType
| Self::Template => false,
}
}
@ -4109,6 +4115,7 @@ impl KnownClass {
Self::UnionType => "UnionType",
Self::MethodWrapperType => "MethodWrapperType",
Self::WrapperDescriptorType => "WrapperDescriptorType",
Self::BuiltinFunctionType => "BuiltinFunctionType",
Self::GeneratorType => "GeneratorType",
Self::AsyncGeneratorType => "AsyncGeneratorType",
Self::CoroutineType => "CoroutineType",
@ -4385,6 +4392,7 @@ impl KnownClass {
| Self::CoroutineType
| Self::MethodWrapperType
| Self::UnionType
| Self::BuiltinFunctionType
| Self::WrapperDescriptorType => KnownModule::Types,
Self::NoneType => KnownModule::Typeshed,
Self::Awaitable
@ -4511,6 +4519,7 @@ impl KnownClass {
| Self::NamedTupleFallback
| Self::NamedTupleLike
| Self::TypedDictFallback
| Self::BuiltinFunctionType
| Self::Template => Some(false),
Self::Tuple => None,
@ -4593,6 +4602,7 @@ impl KnownClass {
| Self::NamedTupleFallback
| Self::NamedTupleLike
| Self::TypedDictFallback
| Self::BuiltinFunctionType
| Self::Template => false,
}
}
@ -4641,6 +4651,7 @@ impl KnownClass {
"UnionType" => Self::UnionType,
"MethodWrapperType" => Self::MethodWrapperType,
"WrapperDescriptorType" => Self::WrapperDescriptorType,
"BuiltinFunctionType" => Self::BuiltinFunctionType,
"NewType" => Self::NewType,
"TypeAliasType" => Self::TypeAliasType,
"TypeVar" => Self::TypeVar,
@ -4743,6 +4754,7 @@ impl KnownClass {
| Self::AsyncGeneratorType
| Self::CoroutineType
| Self::WrapperDescriptorType
| Self::BuiltinFunctionType
| Self::Field
| Self::KwOnly
| Self::InitVar

View file

@ -140,7 +140,7 @@ impl<'db> ClassBase<'db> {
| Type::FunctionLiteral(_)
| Type::Callable(..)
| Type::BoundMethod(_)
| Type::MethodWrapper(_)
| Type::KnownBoundMethod(_)
| Type::WrapperDescriptor(_)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)

View file

@ -16,8 +16,8 @@ use crate::types::generics::{GenericContext, Specialization};
use crate::types::signatures::{CallableSignature, Parameter, Parameters, Signature};
use crate::types::tuple::TupleSpec;
use crate::types::{
BoundTypeVarInstance, CallableType, IntersectionType, KnownClass, MaterializationKind,
MethodWrapperKind, Protocol, ProtocolInstanceType, StringLiteralType, SubclassOfInner, Type,
BoundTypeVarInstance, CallableType, IntersectionType, KnownBoundMethodType, KnownClass,
MaterializationKind, Protocol, ProtocolInstanceType, StringLiteralType, SubclassOfInner, Type,
UnionType, WrapperDescriptorKind,
};
use ruff_db::parsed::parsed_module;
@ -368,27 +368,27 @@ impl Display for DisplayRepresentation<'_> {
}
}
}
Type::MethodWrapper(MethodWrapperKind::FunctionTypeDunderGet(function)) => {
Type::KnownBoundMethod(KnownBoundMethodType::FunctionTypeDunderGet(function)) => {
write!(
f,
"<method-wrapper `__get__` of `{function}`>",
function = function.name(self.db),
)
}
Type::MethodWrapper(MethodWrapperKind::FunctionTypeDunderCall(function)) => {
Type::KnownBoundMethod(KnownBoundMethodType::FunctionTypeDunderCall(function)) => {
write!(
f,
"<method-wrapper `__call__` of `{function}`>",
function = function.name(self.db),
)
}
Type::MethodWrapper(MethodWrapperKind::PropertyDunderGet(_)) => {
Type::KnownBoundMethod(KnownBoundMethodType::PropertyDunderGet(_)) => {
f.write_str("<method-wrapper `__get__` of `property` object>")
}
Type::MethodWrapper(MethodWrapperKind::PropertyDunderSet(_)) => {
Type::KnownBoundMethod(KnownBoundMethodType::PropertyDunderSet(_)) => {
f.write_str("<method-wrapper `__set__` of `property` object>")
}
Type::MethodWrapper(MethodWrapperKind::StrStartswith(_)) => {
Type::KnownBoundMethod(KnownBoundMethodType::StrStartswith(_)) => {
f.write_str("<method-wrapper `startswith` of `str` object>")
}
Type::WrapperDescriptor(kind) => {
@ -1353,7 +1353,7 @@ impl Display for DisplayMaybeParenthesizedType<'_> {
|f: &mut Formatter<'_>| write!(f, "({})", self.ty.display_with(self.db, self.settings));
match self.ty {
Type::Callable(_)
| Type::MethodWrapper(_)
| Type::KnownBoundMethod(_)
| Type::FunctionLiteral(_)
| Type::BoundMethod(_)
| Type::Union(_) => write_parentheses(f),

View file

@ -1095,7 +1095,7 @@ fn is_instance_truthiness<'db>(
Type::TypeAlias(alias) => is_instance_truthiness(db, alias.value_type(db), class),
Type::BoundMethod(..)
| Type::MethodWrapper(..)
| Type::KnownBoundMethod(..)
| Type::WrapperDescriptor(..)
| Type::DataclassDecorator(..)
| Type::DataclassTransformer(..)

View file

@ -143,7 +143,7 @@ impl<'db> AllMembers<'db> {
| Type::PropertyInstance(_)
| Type::FunctionLiteral(_)
| Type::BoundMethod(_)
| Type::MethodWrapper(_)
| Type::KnownBoundMethod(_)
| Type::WrapperDescriptor(_)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)

View file

@ -4087,7 +4087,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
| Type::FunctionLiteral(..)
| Type::Callable(..)
| Type::BoundMethod(_)
| Type::MethodWrapper(_)
| Type::KnownBoundMethod(_)
| Type::WrapperDescriptor(_)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
@ -7388,7 +7388,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
Type::FunctionLiteral(_)
| Type::Callable(..)
| Type::WrapperDescriptor(_)
| Type::MethodWrapper(_)
| Type::KnownBoundMethod(_)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
| Type::BoundMethod(_)
@ -7731,7 +7731,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
| Type::Callable(..)
| Type::BoundMethod(_)
| Type::WrapperDescriptor(_)
| Type::MethodWrapper(_)
| Type::KnownBoundMethod(_)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
| Type::ModuleLiteral(_)
@ -7761,7 +7761,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
| Type::Callable(..)
| Type::BoundMethod(_)
| Type::WrapperDescriptor(_)
| Type::MethodWrapper(_)
| Type::KnownBoundMethod(_)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
| Type::ModuleLiteral(_)

View file

@ -240,7 +240,7 @@ impl ClassInfoConstraintFunction {
| Type::Callable(_)
| Type::DataclassDecorator(_)
| Type::Never
| Type::MethodWrapper(_)
| Type::KnownBoundMethod(_)
| Type::ModuleLiteral(_)
| Type::FunctionLiteral(_)
| Type::ProtocolInstance(_)

View file

@ -76,9 +76,9 @@ pub(super) fn union_or_intersection_elements_ordering<'db>(
(Type::BoundMethod(_), _) => Ordering::Less,
(_, Type::BoundMethod(_)) => Ordering::Greater,
(Type::MethodWrapper(left), Type::MethodWrapper(right)) => left.cmp(right),
(Type::MethodWrapper(_), _) => Ordering::Less,
(_, Type::MethodWrapper(_)) => Ordering::Greater,
(Type::KnownBoundMethod(left), Type::KnownBoundMethod(right)) => left.cmp(right),
(Type::KnownBoundMethod(_), _) => Ordering::Less,
(_, Type::KnownBoundMethod(_)) => Ordering::Greater,
(Type::WrapperDescriptor(left), Type::WrapperDescriptor(right)) => left.cmp(right),
(Type::WrapperDescriptor(_), _) => Ordering::Less,

View file

@ -2,7 +2,7 @@ use crate::{
Db, FxIndexSet,
types::{
BoundMethodType, BoundSuperType, BoundTypeVarInstance, CallableType, GenericAlias,
IntersectionType, KnownInstanceType, MethodWrapperKind, NominalInstanceType,
IntersectionType, KnownBoundMethodType, KnownInstanceType, NominalInstanceType,
PropertyInstanceType, ProtocolInstanceType, SubclassOfType, Type, TypeAliasType,
TypeIsType, TypeVarInstance, TypedDictType, UnionType,
class::walk_generic_alias,
@ -81,7 +81,11 @@ pub(crate) trait TypeVisitor<'db> {
walk_protocol_instance_type(db, protocol, self);
}
fn visit_method_wrapper_type(&self, db: &'db dyn Db, method_wrapper: MethodWrapperKind<'db>) {
fn visit_method_wrapper_type(
&self,
db: &'db dyn Db,
method_wrapper: KnownBoundMethodType<'db>,
) {
walk_method_wrapper_type(db, method_wrapper, self);
}
@ -106,7 +110,7 @@ enum NonAtomicType<'db> {
FunctionLiteral(FunctionType<'db>),
BoundMethod(BoundMethodType<'db>),
BoundSuper(BoundSuperType<'db>),
MethodWrapper(MethodWrapperKind<'db>),
MethodWrapper(KnownBoundMethodType<'db>),
Callable(CallableType<'db>),
GenericAlias(GenericAlias<'db>),
KnownInstance(KnownInstanceType<'db>),
@ -158,7 +162,7 @@ impl<'db> From<Type<'db>> for TypeKind<'db> {
Type::BoundSuper(bound_super) => {
TypeKind::NonAtomic(NonAtomicType::BoundSuper(bound_super))
}
Type::MethodWrapper(method_wrapper) => {
Type::KnownBoundMethod(method_wrapper) => {
TypeKind::NonAtomic(NonAtomicType::MethodWrapper(method_wrapper))
}
Type::Callable(callable) => TypeKind::NonAtomic(NonAtomicType::Callable(callable)),