mirror of https://github.com/astral-sh/ruff
[ty] Include all members on `type` in autocompletion suggestions for `type[]` types (#21670)
This commit is contained in:
parent
666f488f1b
commit
53efc82989
|
|
@ -153,6 +153,12 @@ static_assert(has_member(D, "meta_base_attr"))
|
|||
static_assert(has_member(D, "meta_attr"))
|
||||
static_assert(has_member(D, "base_attr"))
|
||||
static_assert(has_member(D, "class_attr"))
|
||||
|
||||
def f(x: type[D]):
|
||||
static_assert(has_member(x, "meta_base_attr"))
|
||||
static_assert(has_member(x, "meta_attr"))
|
||||
static_assert(has_member(x, "base_attr"))
|
||||
static_assert(has_member(x, "class_attr"))
|
||||
```
|
||||
|
||||
### Generic classes
|
||||
|
|
@ -170,6 +176,40 @@ static_assert(has_member(C[int], "base_attr"))
|
|||
static_assert(has_member(C[int](), "base_attr"))
|
||||
```
|
||||
|
||||
Generic classes can also have metaclasses:
|
||||
|
||||
```py
|
||||
class Meta(type):
|
||||
FOO = 42
|
||||
|
||||
class E(Generic[T], metaclass=Meta): ...
|
||||
|
||||
static_assert(has_member(E[int], "FOO"))
|
||||
|
||||
def f(x: type[E[str]]):
|
||||
static_assert(has_member(x, "FOO"))
|
||||
```
|
||||
|
||||
### `type[Any]` and `Any`
|
||||
|
||||
`type[Any]` has all members of `type`.
|
||||
|
||||
```py
|
||||
from typing import Any
|
||||
from ty_extensions import has_member, static_assert
|
||||
|
||||
def f(x: type[Any]):
|
||||
static_assert(has_member(x, "__base__"))
|
||||
static_assert(has_member(x, "__qualname__"))
|
||||
```
|
||||
|
||||
`Any` has all members of `object`, since it is a subtype of `object`:
|
||||
|
||||
```py
|
||||
def f(x: Any):
|
||||
static_assert(has_member(x, "__repr__"))
|
||||
```
|
||||
|
||||
### Other instance-like types
|
||||
|
||||
```py
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use crate::semantic_index::{
|
|||
use crate::types::call::{CallArguments, MatchedArgument};
|
||||
use crate::types::generics::Specialization;
|
||||
use crate::types::signatures::Signature;
|
||||
use crate::types::{CallDunderError, UnionType};
|
||||
use crate::types::{CallDunderError, SubclassOfInner, UnionType};
|
||||
use crate::types::{
|
||||
CallableTypes, ClassBase, ClassLiteral, KnownClass, KnownInstanceType, Type, TypeContext,
|
||||
TypeVarBoundOrConstraints, class::CodeGeneratorKind,
|
||||
|
|
@ -161,9 +161,8 @@ impl<'db> AllMembers<'db> {
|
|||
Type::ClassLiteral(class_literal) => {
|
||||
self.extend_with_class_members(db, ty, class_literal);
|
||||
self.extend_with_synthetic_members(db, ty, class_literal, None);
|
||||
|
||||
if let Type::ClassLiteral(meta_class_literal) = ty.to_meta_type(db) {
|
||||
self.extend_with_class_members(db, ty, meta_class_literal);
|
||||
if let Type::ClassLiteral(metaclass) = class_literal.metaclass(db) {
|
||||
self.extend_with_class_members(db, ty, metaclass);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -171,17 +170,28 @@ impl<'db> AllMembers<'db> {
|
|||
let class_literal = generic_alias.origin(db);
|
||||
self.extend_with_class_members(db, ty, class_literal);
|
||||
self.extend_with_synthetic_members(db, ty, class_literal, None);
|
||||
}
|
||||
|
||||
Type::SubclassOf(subclass_of_type) => {
|
||||
if let Some(class_type) = subclass_of_type.subclass_of().into_class() {
|
||||
let (class_literal, specialization) = class_type.class_literal(db);
|
||||
self.extend_with_class_members(db, ty, class_literal);
|
||||
self.extend_with_synthetic_members(db, ty, class_literal, specialization);
|
||||
if let Type::ClassLiteral(metaclass) = class_literal.metaclass(db) {
|
||||
self.extend_with_class_members(db, ty, metaclass);
|
||||
}
|
||||
}
|
||||
|
||||
Type::Dynamic(_) | Type::Never | Type::AlwaysTruthy | Type::AlwaysFalsy => {}
|
||||
Type::SubclassOf(subclass_of_type) => match subclass_of_type.subclass_of() {
|
||||
SubclassOfInner::Class(class_type) => {
|
||||
let (class_literal, specialization) = class_type.class_literal(db);
|
||||
self.extend_with_class_members(db, ty, class_literal);
|
||||
self.extend_with_synthetic_members(db, ty, class_literal, specialization);
|
||||
if let Type::ClassLiteral(metaclass) = class_literal.metaclass(db) {
|
||||
self.extend_with_class_members(db, ty, metaclass);
|
||||
}
|
||||
}
|
||||
SubclassOfInner::Dynamic(_) => {
|
||||
self.extend_with_type(db, KnownClass::Type.to_instance(db));
|
||||
}
|
||||
},
|
||||
|
||||
Type::Dynamic(_) | Type::Never | Type::AlwaysTruthy | Type::AlwaysFalsy => {
|
||||
self.extend_with_type(db, Type::object());
|
||||
}
|
||||
|
||||
Type::TypeAlias(alias) => self.extend_with_type(db, alias.value_type(db)),
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue