Compare commits
17 Commits
alex/into_
...
jack/new_t
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49942f656c | ||
|
|
e5ca03e1c7 | ||
|
|
2be369f299 | ||
|
|
5d9a8af775 | ||
|
|
5191691d01 | ||
|
|
a88517f13b | ||
|
|
83e3e67cd7 | ||
|
|
d7376bc9ef | ||
|
|
fe8bd215bf | ||
|
|
8368c28ba7 | ||
|
|
e7b093a371 | ||
|
|
5bbeb56feb | ||
|
|
fd181bf986 | ||
|
|
6b81418bdb | ||
|
|
1dbecd3634 | ||
|
|
e59f0b2211 | ||
|
|
790cce4628 |
@@ -336,7 +336,7 @@ impl<'db> SemanticTokenVisitor<'db> {
|
||||
}
|
||||
|
||||
match ty {
|
||||
Type::ClassLiteral(_) => (SemanticTokenType::Class, modifiers),
|
||||
Type::ClassSingleton(_) => (SemanticTokenType::Class, modifiers),
|
||||
Type::NonInferableTypeVar(_) | Type::TypeVar(_) => {
|
||||
(SemanticTokenType::TypeParameter, modifiers)
|
||||
}
|
||||
@@ -370,7 +370,7 @@ impl<'db> SemanticTokenVisitor<'db> {
|
||||
|
||||
// Classify based on the inferred type of the attribute
|
||||
match ty {
|
||||
Type::ClassLiteral(_) => (SemanticTokenType::Class, modifiers),
|
||||
Type::ClassSingleton(_) => (SemanticTokenType::Class, modifiers),
|
||||
Type::FunctionLiteral(_) => {
|
||||
// This is a function accessed as an attribute, likely a method
|
||||
(SemanticTokenType::Method, modifiers)
|
||||
@@ -1373,10 +1373,10 @@ from typing import List
|
||||
|
||||
class MyClass:
|
||||
CONSTANT = 42
|
||||
|
||||
|
||||
def method(self):
|
||||
return \"hello\"
|
||||
|
||||
|
||||
@property
|
||||
def prop(self):
|
||||
return self.CONSTANT
|
||||
@@ -1442,7 +1442,7 @@ u = List.__name__ # __name__ should be variable<CURSOR>
|
||||
"
|
||||
class MyClass:
|
||||
some_attr = \"value\"
|
||||
|
||||
|
||||
obj = MyClass()
|
||||
# Test attribute that might not have detailed semantic info
|
||||
x = obj.some_attr # Should fall back to variable, not property
|
||||
@@ -1476,10 +1476,10 @@ class MyClass:
|
||||
lower_case = 24
|
||||
MixedCase = 12
|
||||
A = 1
|
||||
|
||||
|
||||
obj = MyClass()
|
||||
x = obj.UPPER_CASE # Should have readonly modifier
|
||||
y = obj.lower_case # Should not have readonly modifier
|
||||
y = obj.lower_case # Should not have readonly modifier
|
||||
z = obj.MixedCase # Should not have readonly modifier
|
||||
w = obj.A # Should not have readonly modifier (length == 1)<CURSOR>
|
||||
",
|
||||
@@ -1604,7 +1604,7 @@ def test_function(param: int, other: MyClass) -> Optional[List[str]]:
|
||||
x: int = 42
|
||||
y: MyClass = MyClass()
|
||||
z: List[str] = [\"hello\"]
|
||||
|
||||
|
||||
# Type annotations should be Class tokens:
|
||||
# int, MyClass, Optional, List, str
|
||||
return None<CURSOR>
|
||||
@@ -1683,7 +1683,7 @@ class MyProtocol(Protocol):
|
||||
# Value context - MyProtocol is still a class literal, so should be Class
|
||||
my_protocol_var = MyProtocol
|
||||
|
||||
# Type annotation context - should be Class
|
||||
# Type annotation context - should be Class
|
||||
def test_function(param: MyProtocol) -> MyProtocol:
|
||||
return param
|
||||
<CURSOR>",
|
||||
@@ -1719,7 +1719,7 @@ def test_function(param: MyProtocol) -> MyProtocol:
|
||||
def func[T](x: T) -> T:
|
||||
return x
|
||||
|
||||
# Generic function with TypeVarTuple
|
||||
# Generic function with TypeVarTuple
|
||||
def func_tuple[*Ts](args: tuple[*Ts]) -> tuple[*Ts]:
|
||||
return args
|
||||
|
||||
@@ -1734,10 +1734,10 @@ class Container[T, U]:
|
||||
def __init__(self, value1: T, value2: U):
|
||||
self.value1: T = value1
|
||||
self.value2: U = value2
|
||||
|
||||
|
||||
def get_first(self) -> T:
|
||||
return self.value1
|
||||
|
||||
|
||||
def get_second(self) -> U:
|
||||
return self.value2
|
||||
|
||||
@@ -1892,8 +1892,8 @@ class MyClass:
|
||||
fn test_implicitly_concatenated_strings() {
|
||||
let test = cursor_test(
|
||||
r#"x = "hello" "world"
|
||||
y = ("multi"
|
||||
"line"
|
||||
y = ("multi"
|
||||
"line"
|
||||
"string")
|
||||
z = 'single' "mixed" 'quotes'<CURSOR>"#,
|
||||
);
|
||||
@@ -1919,8 +1919,8 @@ z = 'single' "mixed" 'quotes'<CURSOR>"#,
|
||||
fn test_bytes_literals() {
|
||||
let test = cursor_test(
|
||||
r#"x = b"hello" b"world"
|
||||
y = (b"multi"
|
||||
b"line"
|
||||
y = (b"multi"
|
||||
b"line"
|
||||
b"bytes")
|
||||
z = b'single' b"mixed" b'quotes'<CURSOR>"#,
|
||||
);
|
||||
@@ -2040,21 +2040,21 @@ y = "another_global"
|
||||
def outer():
|
||||
x = "outer_value"
|
||||
z = "outer_local"
|
||||
|
||||
|
||||
def inner():
|
||||
nonlocal x, z # These should be variable tokens
|
||||
global y # This should be a variable token
|
||||
x = "modified"
|
||||
y = "modified_global"
|
||||
z = "modified_local"
|
||||
|
||||
|
||||
def deeper():
|
||||
nonlocal x # Variable token
|
||||
global y, x # Both should be variable tokens
|
||||
return x + y
|
||||
|
||||
|
||||
return deeper
|
||||
|
||||
|
||||
return inner<CURSOR>
|
||||
"#,
|
||||
);
|
||||
@@ -2100,11 +2100,11 @@ def outer():
|
||||
def test():
|
||||
global x
|
||||
nonlocal y
|
||||
|
||||
|
||||
# Multiple variables in one statement
|
||||
global a, b, c
|
||||
nonlocal d, e, f
|
||||
|
||||
|
||||
return x + y + a + b + c + d + e + f<CURSOR>
|
||||
"#,
|
||||
);
|
||||
|
||||
@@ -1323,7 +1323,7 @@ mod implicit_globals {
|
||||
{
|
||||
return Place::Unbound.into();
|
||||
}
|
||||
let Type::ClassLiteral(module_type_class) = KnownClass::ModuleType.to_class_literal(db)
|
||||
let Type::ClassSingleton(module_type_class) = KnownClass::ModuleType.to_class_singleton(db)
|
||||
else {
|
||||
return Place::Unbound.into();
|
||||
};
|
||||
@@ -1402,8 +1402,8 @@ mod implicit_globals {
|
||||
#[salsa::tracked(returns(deref), heap_size=ruff_memory_usage::heap_size)]
|
||||
fn module_type_symbols<'db>(db: &'db dyn Db) -> smallvec::SmallVec<[ast::name::Name; 8]> {
|
||||
let Some(module_type) = KnownClass::ModuleType
|
||||
.to_class_literal(db)
|
||||
.into_class_literal()
|
||||
.to_class_singleton(db)
|
||||
.into_class_singleton()
|
||||
else {
|
||||
// The most likely way we get here is if a user specified a `--custom-typeshed-dir`
|
||||
// without a `types.pyi` stub in the `stdlib/` directory
|
||||
|
||||
@@ -215,7 +215,7 @@ impl<'db> Completion<'db> {
|
||||
| Type::Callable(_) => CompletionKind::Function,
|
||||
Type::BoundMethod(_) | Type::MethodWrapper(_) => CompletionKind::Method,
|
||||
Type::ModuleLiteral(_) => CompletionKind::Module,
|
||||
Type::ClassLiteral(_) | Type::GenericAlias(_) | Type::SubclassOf(_) => {
|
||||
Type::ClassSingleton(_) | Type::GenericAlias(_) | Type::SubclassOf(_) => {
|
||||
CompletionKind::Class
|
||||
}
|
||||
// This is a little weird for "struct." I'm mostly interpreting
|
||||
@@ -474,7 +474,7 @@ mod tests {
|
||||
let model = SemanticModel::new(&db, foo);
|
||||
let ty = class.inferred_type(&model);
|
||||
|
||||
assert!(ty.is_class_literal());
|
||||
assert!(ty.is_class_singleton());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -495,7 +495,7 @@ mod tests {
|
||||
let model = SemanticModel::new(&db, bar);
|
||||
let ty = alias.inferred_type(&model);
|
||||
|
||||
assert!(ty.is_class_literal());
|
||||
assert!(ty.is_class_singleton());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ use crate::types::tuple::TupleSpec;
|
||||
use crate::unpack::EvaluationMode;
|
||||
pub use crate::util::diagnostics::add_inferred_python_version_hint_to_diagnostic;
|
||||
use crate::{Db, FxOrderMap, FxOrderSet, Module, Program};
|
||||
pub(crate) use class::{ClassLiteral, ClassType, GenericAlias, KnownClass};
|
||||
pub(crate) use class::{ClassSingletonType, ClassType, GenericAlias, KnownClass};
|
||||
use instance::Protocol;
|
||||
pub use instance::{NominalInstanceType, ProtocolInstanceType};
|
||||
pub use special_form::SpecialFormType;
|
||||
@@ -569,7 +569,7 @@ pub enum Type<'db> {
|
||||
/// A specific module object
|
||||
ModuleLiteral(ModuleLiteralType<'db>),
|
||||
/// A specific class object
|
||||
ClassLiteral(ClassLiteral<'db>),
|
||||
ClassSingleton(ClassSingletonType<'db>),
|
||||
/// A specialization of a generic class
|
||||
GenericAlias(GenericAlias<'db>),
|
||||
/// The set of all class objects that are subclasses of the given class (C), spelled `type[C]`.
|
||||
@@ -781,7 +781,7 @@ impl<'db> Type<'db> {
|
||||
| Type::KnownInstance(_)
|
||||
| Type::AlwaysFalsy
|
||||
| Type::AlwaysTruthy
|
||||
| Type::ClassLiteral(_)
|
||||
| Type::ClassSingleton(_)
|
||||
| Type::BoundSuper(_) => *self,
|
||||
|
||||
Type::PropertyInstance(property_instance) => {
|
||||
@@ -842,17 +842,17 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn into_class_literal(self) -> Option<ClassLiteral<'db>> {
|
||||
pub(crate) const fn into_class_singleton(self) -> Option<ClassSingletonType<'db>> {
|
||||
match self {
|
||||
Type::ClassLiteral(class_type) => Some(class_type),
|
||||
Type::ClassSingleton(class_type) => Some(class_type),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub(crate) fn expect_class_literal(self) -> ClassLiteral<'db> {
|
||||
self.into_class_literal()
|
||||
.expect("Expected a Type::ClassLiteral variant")
|
||||
pub(crate) fn expect_class_singleton(self) -> ClassSingletonType<'db> {
|
||||
self.into_class_singleton()
|
||||
.expect("Expected a Type::ClassSingleton variant")
|
||||
}
|
||||
|
||||
pub(crate) const fn is_subclass_of(&self) -> bool {
|
||||
@@ -860,8 +860,8 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) const fn is_class_literal(&self) -> bool {
|
||||
matches!(self, Type::ClassLiteral(..))
|
||||
pub(crate) const fn is_class_singleton(&self) -> bool {
|
||||
matches!(self, Type::ClassSingleton(..))
|
||||
}
|
||||
|
||||
pub(crate) fn into_enum_literal(self) -> Option<EnumLiteralType<'db>> {
|
||||
@@ -889,12 +889,12 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Turn a class literal (`Type::ClassLiteral` or `Type::GenericAlias`) into a `ClassType`.
|
||||
/// Turn a class literal (`Type::ClassSingleton` or `Type::GenericAlias`) into a `ClassType`.
|
||||
/// Since a `ClassType` must be specialized, apply the default specialization to any
|
||||
/// unspecialized generic class literal.
|
||||
pub(crate) fn to_class_type(self, db: &'db dyn Db) -> Option<ClassType<'db>> {
|
||||
match self {
|
||||
Type::ClassLiteral(class_literal) => Some(class_literal.default_specialization(db)),
|
||||
Type::ClassSingleton(singleton) => Some(singleton.default_specialization(db)),
|
||||
Type::GenericAlias(alias) => Some(ClassType::Generic(alias)),
|
||||
_ => None,
|
||||
}
|
||||
@@ -1112,7 +1112,7 @@ impl<'db> Type<'db> {
|
||||
| Type::DataclassDecorator(_)
|
||||
| Type::DataclassTransformer(_)
|
||||
| Type::ModuleLiteral(_)
|
||||
| Type::ClassLiteral(_)
|
||||
| Type::ClassSingleton(_)
|
||||
| Type::SpecialForm(_)
|
||||
| Type::IntLiteral(_) => self,
|
||||
}
|
||||
@@ -1122,7 +1122,7 @@ impl<'db> Type<'db> {
|
||||
/// any `T` of this type.
|
||||
///
|
||||
/// This is true for fully static types, but also for some types that may not be fully static.
|
||||
/// For example, a `ClassLiteral` may inherit `Any`, but its subtyping is still reflexive.
|
||||
/// For example, a `ClassSingleton` may inherit `Any`, but its subtyping is still reflexive.
|
||||
///
|
||||
/// This method may have false negatives, but it should not have false positives. It should be
|
||||
/// a cheap shallow check, not an exhaustive recursive check.
|
||||
@@ -1148,7 +1148,7 @@ impl<'db> Type<'db> {
|
||||
| Type::AlwaysTruthy
|
||||
| Type::PropertyInstance(_)
|
||||
// might inherit `Any`, but subtyping is still reflexive
|
||||
| Type::ClassLiteral(_)
|
||||
| Type::ClassSingleton(_)
|
||||
=> true,
|
||||
Type::Dynamic(_)
|
||||
| Type::NominalInstance(_)
|
||||
@@ -1195,8 +1195,8 @@ impl<'db> Type<'db> {
|
||||
None
|
||||
}
|
||||
}
|
||||
Type::ClassLiteral(class_literal) => {
|
||||
Some(ClassType::NonGeneric(class_literal).into_callable(db))
|
||||
Type::ClassSingleton(singleton) => {
|
||||
Some(ClassType::NonGeneric(singleton).into_callable(db))
|
||||
}
|
||||
|
||||
Type::GenericAlias(alias) => Some(ClassType::Generic(alias).into_callable(db)),
|
||||
@@ -1493,14 +1493,14 @@ impl<'db> Type<'db> {
|
||||
Type::StringLiteral(_)
|
||||
| Type::IntLiteral(_)
|
||||
| Type::BytesLiteral(_)
|
||||
| Type::ClassLiteral(_)
|
||||
| Type::ClassSingleton(_)
|
||||
| Type::FunctionLiteral(_)
|
||||
| Type::ModuleLiteral(_)
|
||||
| Type::EnumLiteral(_),
|
||||
Type::StringLiteral(_)
|
||||
| Type::IntLiteral(_)
|
||||
| Type::BytesLiteral(_)
|
||||
| Type::ClassLiteral(_)
|
||||
| Type::ClassSingleton(_)
|
||||
| Type::FunctionLiteral(_)
|
||||
| Type::ModuleLiteral(_)
|
||||
| Type::EnumLiteral(_),
|
||||
@@ -1613,18 +1613,20 @@ impl<'db> Type<'db> {
|
||||
|
||||
// `Literal[<class 'C'>]` is a subtype of `type[B]` if `C` is a subclass of `B`,
|
||||
// since `type[B]` describes all possible runtime subclasses of the class object `B`.
|
||||
(Type::ClassLiteral(class), Type::SubclassOf(target_subclass_ty)) => target_subclass_ty
|
||||
.subclass_of()
|
||||
.into_class()
|
||||
.map(|subclass_of_class| {
|
||||
ClassType::NonGeneric(class).has_relation_to_impl(
|
||||
db,
|
||||
subclass_of_class,
|
||||
relation,
|
||||
visitor,
|
||||
)
|
||||
})
|
||||
.unwrap_or(relation.is_assignability()),
|
||||
(Type::ClassSingleton(class), Type::SubclassOf(target_subclass_ty)) => {
|
||||
target_subclass_ty
|
||||
.subclass_of()
|
||||
.into_class()
|
||||
.map(|subclass_of_class| {
|
||||
ClassType::NonGeneric(class).has_relation_to_impl(
|
||||
db,
|
||||
subclass_of_class,
|
||||
relation,
|
||||
visitor,
|
||||
)
|
||||
})
|
||||
.unwrap_or(relation.is_assignability())
|
||||
}
|
||||
(Type::GenericAlias(alias), Type::SubclassOf(target_subclass_ty)) => target_subclass_ty
|
||||
.subclass_of()
|
||||
.into_class()
|
||||
@@ -1646,7 +1648,7 @@ impl<'db> Type<'db> {
|
||||
// `Literal[str]` is a subtype of `type` because the `str` class object is an instance of its metaclass `type`.
|
||||
// `Literal[abc.ABC]` is a subtype of `abc.ABCMeta` because the `abc.ABC` class object
|
||||
// is an instance of its metaclass `abc.ABCMeta`.
|
||||
(Type::ClassLiteral(class), _) => class
|
||||
(Type::ClassSingleton(class), _) => class
|
||||
.metaclass_instance_type(db)
|
||||
.has_relation_to_impl(db, target, relation, visitor),
|
||||
(Type::GenericAlias(alias), _) => ClassType::from(alias)
|
||||
@@ -1810,8 +1812,8 @@ impl<'db> Type<'db> {
|
||||
return false;
|
||||
}
|
||||
|
||||
let class_literal = instance.class(db).class_literal(db).0;
|
||||
is_single_member_enum(db, class_literal)
|
||||
let singleton = instance.class(db).class_singleton(db).0;
|
||||
is_single_member_enum(db, singleton)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
@@ -1955,7 +1957,7 @@ impl<'db> Type<'db> {
|
||||
| Type::MethodWrapper(..)
|
||||
| Type::WrapperDescriptor(..)
|
||||
| Type::ModuleLiteral(..)
|
||||
| Type::ClassLiteral(..)
|
||||
| Type::ClassSingleton(..)
|
||||
| Type::GenericAlias(..)
|
||||
| Type::SpecialForm(..)
|
||||
| Type::KnownInstance(..)),
|
||||
@@ -1969,7 +1971,7 @@ impl<'db> Type<'db> {
|
||||
| Type::MethodWrapper(..)
|
||||
| Type::WrapperDescriptor(..)
|
||||
| Type::ModuleLiteral(..)
|
||||
| Type::ClassLiteral(..)
|
||||
| Type::ClassSingleton(..)
|
||||
| Type::GenericAlias(..)
|
||||
| Type::SpecialForm(..)
|
||||
| Type::KnownInstance(..)),
|
||||
@@ -2061,7 +2063,7 @@ impl<'db> Type<'db> {
|
||||
| Type::StringLiteral(..)
|
||||
| Type::BytesLiteral(..)
|
||||
| Type::BooleanLiteral(..)
|
||||
| Type::ClassLiteral(..)
|
||||
| Type::ClassSingleton(..)
|
||||
| Type::FunctionLiteral(..)
|
||||
| Type::ModuleLiteral(..)
|
||||
| Type::GenericAlias(..)
|
||||
@@ -2076,7 +2078,7 @@ impl<'db> Type<'db> {
|
||||
| Type::StringLiteral(..)
|
||||
| Type::BytesLiteral(..)
|
||||
| Type::BooleanLiteral(..)
|
||||
| Type::ClassLiteral(..)
|
||||
| Type::ClassSingleton(..)
|
||||
| Type::FunctionLiteral(..)
|
||||
| Type::ModuleLiteral(..)
|
||||
| Type::GenericAlias(..)
|
||||
@@ -2104,8 +2106,8 @@ impl<'db> Type<'db> {
|
||||
})
|
||||
}),
|
||||
|
||||
(Type::SubclassOf(subclass_of_ty), Type::ClassLiteral(class_b))
|
||||
| (Type::ClassLiteral(class_b), Type::SubclassOf(subclass_of_ty)) => {
|
||||
(Type::SubclassOf(subclass_of_ty), Type::ClassSingleton(class_b))
|
||||
| (Type::ClassSingleton(class_b), Type::SubclassOf(subclass_of_ty)) => {
|
||||
match subclass_of_ty.subclass_of() {
|
||||
SubclassOfInner::Dynamic(_) => false,
|
||||
SubclassOfInner::Class(class_a) => !class_b.is_subclass_of(db, None, class_a),
|
||||
@@ -2194,8 +2196,8 @@ impl<'db> Type<'db> {
|
||||
// A class-literal type `X` is always disjoint from an instance type `Y`,
|
||||
// unless the type expressing "all instances of `Z`" is a subtype of of `Y`,
|
||||
// where `Z` is `X`'s metaclass.
|
||||
(Type::ClassLiteral(class), instance @ Type::NominalInstance(_))
|
||||
| (instance @ Type::NominalInstance(_), Type::ClassLiteral(class)) => !class
|
||||
(Type::ClassSingleton(class), instance @ Type::NominalInstance(_))
|
||||
| (instance @ Type::NominalInstance(_), Type::ClassSingleton(class)) => !class
|
||||
.metaclass_instance_type(db)
|
||||
.is_subtype_of(db, instance),
|
||||
(Type::GenericAlias(alias), instance @ Type::NominalInstance(_))
|
||||
@@ -2363,13 +2365,13 @@ impl<'db> Type<'db> {
|
||||
|
||||
Type::TypeVar(_) => false,
|
||||
|
||||
// We eagerly transform `SubclassOf` to `ClassLiteral` for final types, so `SubclassOf` is never a singleton.
|
||||
// We eagerly transform `SubclassOf` to `ClassSingleton` for final types, so `SubclassOf` is never a singleton.
|
||||
Type::SubclassOf(..) => false,
|
||||
Type::BoundSuper(..) => false,
|
||||
Type::BooleanLiteral(_)
|
||||
| Type::FunctionLiteral(..)
|
||||
| Type::WrapperDescriptor(..)
|
||||
| Type::ClassLiteral(..)
|
||||
| Type::ClassSingleton(..)
|
||||
| Type::GenericAlias(..)
|
||||
| Type::ModuleLiteral(..)
|
||||
| Type::EnumLiteral(..) => true,
|
||||
@@ -2439,7 +2441,7 @@ impl<'db> Type<'db> {
|
||||
| Type::WrapperDescriptor(_)
|
||||
| Type::MethodWrapper(_)
|
||||
| Type::ModuleLiteral(..)
|
||||
| Type::ClassLiteral(..)
|
||||
| Type::ClassSingleton(..)
|
||||
| Type::GenericAlias(..)
|
||||
| Type::IntLiteral(..)
|
||||
| Type::BooleanLiteral(..)
|
||||
@@ -2562,11 +2564,11 @@ impl<'db> Type<'db> {
|
||||
|
||||
Type::Dynamic(_) | Type::Never => Some(Place::bound(self).into()),
|
||||
|
||||
Type::ClassLiteral(class) if class.is_typed_dict(db) => {
|
||||
Type::ClassSingleton(class) if class.is_typed_dict(db) => {
|
||||
Some(class.typed_dict_member(db, None, name, policy))
|
||||
}
|
||||
|
||||
Type::ClassLiteral(class) => {
|
||||
Type::ClassSingleton(class) => {
|
||||
match (class.known(db), name) {
|
||||
(Some(KnownClass::FunctionType), "__get__") => Some(
|
||||
Place::bound(Type::WrapperDescriptor(
|
||||
@@ -2610,7 +2612,7 @@ impl<'db> Type<'db> {
|
||||
// Note: `super(pivot, owner).__class__` is `builtins.super`, not the owner's class.
|
||||
// `BoundSuper` should look up the name in the MRO of `builtins.super`.
|
||||
Type::BoundSuper(_) => KnownClass::Super
|
||||
.to_class_literal(db)
|
||||
.to_class_singleton(db)
|
||||
.find_name_in_mro_with_policy(db, name, policy),
|
||||
|
||||
// We eagerly normalize type[object], i.e. Type::SubclassOf(object) to `type`,
|
||||
@@ -2624,7 +2626,7 @@ impl<'db> Type<'db> {
|
||||
Some(Place::Unbound.into())
|
||||
} else {
|
||||
KnownClass::Object
|
||||
.to_class_literal(db)
|
||||
.to_class_singleton(db)
|
||||
.find_name_in_mro_with_policy(db, name, policy)
|
||||
}
|
||||
}
|
||||
@@ -2819,7 +2821,7 @@ impl<'db> Type<'db> {
|
||||
// a `__dict__` that is filled with class level attributes. Modeling this is currently not
|
||||
// required, as `instance_member` is only called for instance-like types through `member`,
|
||||
// but we might want to add this in the future.
|
||||
Type::ClassLiteral(_) | Type::GenericAlias(_) | Type::SubclassOf(_) => {
|
||||
Type::ClassSingleton(_) | Type::GenericAlias(_) | Type::SubclassOf(_) => {
|
||||
Place::Unbound.into()
|
||||
}
|
||||
|
||||
@@ -3200,7 +3202,7 @@ impl<'db> Type<'db> {
|
||||
)
|
||||
.into(),
|
||||
|
||||
Type::ClassLiteral(class)
|
||||
Type::ClassSingleton(class)
|
||||
if name == "__get__" && class.is_known(db, KnownClass::FunctionType) =>
|
||||
{
|
||||
Place::bound(Type::WrapperDescriptor(
|
||||
@@ -3208,7 +3210,7 @@ impl<'db> Type<'db> {
|
||||
))
|
||||
.into()
|
||||
}
|
||||
Type::ClassLiteral(class)
|
||||
Type::ClassSingleton(class)
|
||||
if name == "__get__" && class.is_known(db, KnownClass::Property) =>
|
||||
{
|
||||
Place::bound(Type::WrapperDescriptor(
|
||||
@@ -3216,7 +3218,7 @@ impl<'db> Type<'db> {
|
||||
))
|
||||
.into()
|
||||
}
|
||||
Type::ClassLiteral(class)
|
||||
Type::ClassSingleton(class)
|
||||
if name == "__set__" && class.is_known(db, KnownClass::Property) =>
|
||||
{
|
||||
Place::bound(Type::WrapperDescriptor(
|
||||
@@ -3402,7 +3404,7 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
Type::ClassLiteral(..) | Type::GenericAlias(..) | Type::SubclassOf(..) => {
|
||||
Type::ClassSingleton(..) | Type::GenericAlias(..) | Type::SubclassOf(..) => {
|
||||
let class_attr_plain = self.find_name_in_mro_with_policy(db, name_str,policy).expect(
|
||||
"Calling `find_name_in_mro` on class literals and subclass-of types should always return `Some`",
|
||||
);
|
||||
@@ -3412,11 +3414,11 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
|
||||
if let Some(enum_class) = match self {
|
||||
Type::ClassLiteral(literal) => Some(literal),
|
||||
Type::ClassSingleton(literal) => Some(literal),
|
||||
Type::SubclassOf(subclass_of) => subclass_of
|
||||
.subclass_of()
|
||||
.into_class()
|
||||
.map(|class| class.class_literal(db).0),
|
||||
.map(|class| class.class_singleton(db).0),
|
||||
_ => None,
|
||||
} {
|
||||
if let Some(metadata) = enum_metadata(db, enum_class) {
|
||||
@@ -3633,7 +3635,7 @@ impl<'db> Type<'db> {
|
||||
|
||||
Type::AlwaysFalsy => Truthiness::AlwaysFalse,
|
||||
|
||||
Type::ClassLiteral(class) => class
|
||||
Type::ClassSingleton(class) => class
|
||||
.metaclass_instance_type(db)
|
||||
.try_bool_impl(db, allow_short_circuit)?,
|
||||
Type::GenericAlias(alias) => ClassType::from(*alias)
|
||||
@@ -4141,7 +4143,7 @@ impl<'db> Type<'db> {
|
||||
.into(),
|
||||
},
|
||||
|
||||
Type::ClassLiteral(class) => match class.known(db) {
|
||||
Type::ClassSingleton(class) => match class.known(db) {
|
||||
// TODO: Ideally we'd use `try_call_constructor` for all constructor calls.
|
||||
// Currently we don't for a few special known types, either because their
|
||||
// constructors are defined with overloads, or because we want to special case
|
||||
@@ -4257,6 +4259,20 @@ impl<'db> Type<'db> {
|
||||
.into()
|
||||
}
|
||||
|
||||
Some(KnownClass::NewType) => Binding::single(
|
||||
self,
|
||||
Signature::new(
|
||||
Parameters::new([
|
||||
Parameter::positional_or_keyword(Name::new_static("name"))
|
||||
.with_annotated_type(Type::LiteralString),
|
||||
Parameter::positional_or_keyword(Name::new_static("tp")),
|
||||
]),
|
||||
// TODO: What should this return type be?
|
||||
Some(KnownClass::NewType.to_instance(db)),
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
|
||||
Some(KnownClass::Object) => {
|
||||
// ```py
|
||||
// class object:
|
||||
@@ -5047,7 +5063,7 @@ impl<'db> Type<'db> {
|
||||
let from_class_base = |base: ClassBase<'db>| {
|
||||
let class = base.into_class()?;
|
||||
if class.is_known(db, KnownClass::Generator) {
|
||||
if let Some(specialization) = class.class_literal_specialized(db, None).1 {
|
||||
if let Some(specialization) = class.singleton_specialized(db, None).1 {
|
||||
if let [_, _, return_ty] = specialization.types(db) {
|
||||
return Some(*return_ty);
|
||||
}
|
||||
@@ -5093,7 +5109,7 @@ impl<'db> Type<'db> {
|
||||
) -> Result<Type<'db>, ConstructorCallError<'db>> {
|
||||
debug_assert!(matches!(
|
||||
self,
|
||||
Type::ClassLiteral(_) | Type::GenericAlias(_) | Type::SubclassOf(_)
|
||||
Type::ClassSingleton(_) | Type::GenericAlias(_) | Type::SubclassOf(_)
|
||||
));
|
||||
|
||||
// If we are trying to construct a non-specialized generic class, we should use the
|
||||
@@ -5105,7 +5121,7 @@ impl<'db> Type<'db> {
|
||||
// do this, we instead use the _identity_ specialization, which maps each of the class's
|
||||
// generic typevars to itself.
|
||||
let (generic_origin, generic_context, self_type) = match self {
|
||||
Type::ClassLiteral(class) => match class.generic_context(db) {
|
||||
Type::ClassSingleton(class) => match class.generic_context(db) {
|
||||
Some(generic_context) => (
|
||||
Some(class),
|
||||
Some(generic_context),
|
||||
@@ -5269,7 +5285,9 @@ impl<'db> Type<'db> {
|
||||
pub(crate) fn to_instance(self, db: &'db dyn Db) -> Option<Type<'db>> {
|
||||
match self {
|
||||
Type::Dynamic(_) | Type::Never => Some(self),
|
||||
Type::ClassLiteral(class) => Some(Type::instance(db, class.default_specialization(db))),
|
||||
Type::ClassSingleton(class) => {
|
||||
Some(Type::instance(db, class.default_specialization(db)))
|
||||
}
|
||||
Type::GenericAlias(alias) => Some(Type::instance(db, ClassType::from(alias))),
|
||||
Type::SubclassOf(subclass_of_ty) => Some(subclass_of_ty.to_instance(db)),
|
||||
Type::Union(union) => union.to_instance(db),
|
||||
@@ -5312,7 +5330,7 @@ impl<'db> Type<'db> {
|
||||
/// If we see a value of this type used as a type expression, what type does it name?
|
||||
///
|
||||
/// For example, the builtin `int` as a value expression is of type
|
||||
/// `Type::ClassLiteral(builtins.int)`, that is, it is the `int` class itself. As a type
|
||||
/// `Type::ClassSingleton(ClassSingletonType::Literal(builtins.int))`, that is, it is the `int` class itself. As a type
|
||||
/// expression, it names the type `Type::NominalInstance(builtins.int)`, that is, all objects whose
|
||||
/// `__class__` is `int`.
|
||||
///
|
||||
@@ -5327,7 +5345,7 @@ impl<'db> Type<'db> {
|
||||
match self {
|
||||
// Special cases for `float` and `complex`
|
||||
// https://typing.python.org/en/latest/spec/special-types.html#special-cases-for-float-and-complex
|
||||
Type::ClassLiteral(class) => {
|
||||
Type::ClassSingleton(class) => {
|
||||
let ty = match class.known(db) {
|
||||
Some(KnownClass::Any) => Type::any(),
|
||||
Some(KnownClass::Complex) => UnionType::from_elements(
|
||||
@@ -5469,7 +5487,7 @@ impl<'db> Type<'db> {
|
||||
],
|
||||
});
|
||||
};
|
||||
let instance = Type::ClassLiteral(class).to_instance(db).expect(
|
||||
let instance = Type::ClassSingleton(class).to_instance(db).expect(
|
||||
"nearest_enclosing_class must return type that can be instantiated",
|
||||
);
|
||||
let class_definition = class.definition(db);
|
||||
@@ -5643,22 +5661,22 @@ impl<'db> Type<'db> {
|
||||
Type::NominalInstance(instance) => instance.to_meta_type(db),
|
||||
Type::KnownInstance(known_instance) => known_instance.to_meta_type(db),
|
||||
Type::SpecialForm(special_form) => special_form.to_meta_type(db),
|
||||
Type::PropertyInstance(_) => KnownClass::Property.to_class_literal(db),
|
||||
Type::PropertyInstance(_) => KnownClass::Property.to_class_singleton(db),
|
||||
Type::Union(union) => union.map(db, |ty| ty.to_meta_type(db)),
|
||||
Type::BooleanLiteral(_) | Type::TypeIs(_) => KnownClass::Bool.to_class_literal(db),
|
||||
Type::BytesLiteral(_) => KnownClass::Bytes.to_class_literal(db),
|
||||
Type::IntLiteral(_) => KnownClass::Int.to_class_literal(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::WrapperDescriptor(_) => KnownClass::WrapperDescriptorType.to_class_literal(db),
|
||||
Type::DataclassDecorator(_) => KnownClass::FunctionType.to_class_literal(db),
|
||||
Type::BooleanLiteral(_) | Type::TypeIs(_) => KnownClass::Bool.to_class_singleton(db),
|
||||
Type::BytesLiteral(_) => KnownClass::Bytes.to_class_singleton(db),
|
||||
Type::IntLiteral(_) => KnownClass::Int.to_class_singleton(db),
|
||||
Type::EnumLiteral(enum_literal) => Type::ClassSingleton(enum_literal.enum_class(db)),
|
||||
Type::FunctionLiteral(_) => KnownClass::FunctionType.to_class_singleton(db),
|
||||
Type::BoundMethod(_) => KnownClass::MethodType.to_class_singleton(db),
|
||||
Type::MethodWrapper(_) => KnownClass::MethodWrapperType.to_class_singleton(db),
|
||||
Type::WrapperDescriptor(_) => KnownClass::WrapperDescriptorType.to_class_singleton(db),
|
||||
Type::DataclassDecorator(_) => KnownClass::FunctionType.to_class_singleton(db),
|
||||
Type::Callable(callable) if callable.is_function_like(db) => {
|
||||
KnownClass::FunctionType.to_class_literal(db)
|
||||
KnownClass::FunctionType.to_class_singleton(db)
|
||||
}
|
||||
Type::Callable(_) | Type::DataclassTransformer(_) => KnownClass::Type.to_instance(db),
|
||||
Type::ModuleLiteral(_) => KnownClass::ModuleType.to_class_literal(db),
|
||||
Type::ModuleLiteral(_) => KnownClass::ModuleType.to_class_singleton(db),
|
||||
Type::NonInferableTypeVar(bound_typevar) => {
|
||||
match bound_typevar.typevar(db).bound_or_constraints(db) {
|
||||
None => KnownClass::Type.to_instance(db),
|
||||
@@ -5672,7 +5690,7 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
Type::TypeVar(_) => KnownClass::Type.to_instance(db),
|
||||
|
||||
Type::ClassLiteral(class) => class.metaclass(db),
|
||||
Type::ClassSingleton(class) => class.metaclass(db),
|
||||
Type::GenericAlias(alias) => ClassType::from(alias).metaclass(db),
|
||||
Type::SubclassOf(subclass_of_ty) => match subclass_of_ty.subclass_of() {
|
||||
SubclassOfInner::Dynamic(_) => self,
|
||||
@@ -5683,7 +5701,7 @@ impl<'db> Type<'db> {
|
||||
),
|
||||
},
|
||||
|
||||
Type::StringLiteral(_) | Type::LiteralString => KnownClass::Str.to_class_literal(db),
|
||||
Type::StringLiteral(_) | Type::LiteralString => KnownClass::Str.to_class_singleton(db),
|
||||
Type::Dynamic(dynamic) => SubclassOfType::from(db, SubclassOfInner::Dynamic(dynamic)),
|
||||
// TODO intersections
|
||||
Type::Intersection(_) => SubclassOfType::from(
|
||||
@@ -5692,7 +5710,7 @@ impl<'db> Type<'db> {
|
||||
.expect("Type::Todo should be a valid `SubclassOfInner`"),
|
||||
),
|
||||
Type::AlwaysTruthy | Type::AlwaysFalsy => KnownClass::Type.to_instance(db),
|
||||
Type::BoundSuper(_) => KnownClass::Super.to_class_literal(db),
|
||||
Type::BoundSuper(_) => KnownClass::Super.to_class_singleton(db),
|
||||
Type::ProtocolInstance(protocol) => protocol.to_meta_type(db),
|
||||
Type::TypedDict(typed_dict) => SubclassOfType::from(db, typed_dict.defining_class),
|
||||
Type::TypeAlias(alias) => alias.value_type(db).to_meta_type(db),
|
||||
@@ -5919,7 +5937,7 @@ impl<'db> Type<'db> {
|
||||
// A non-generic class never needs to be specialized. A generic class is specialized
|
||||
// explicitly (via a subscript expression) or implicitly (via a call), and not because
|
||||
// some other generic context's specialization is applied to it.
|
||||
| Type::ClassLiteral(_)
|
||||
| Type::ClassSingleton(_)
|
||||
| Type::BoundSuper(_)
|
||||
| Type::SpecialForm(_)
|
||||
| Type::KnownInstance(_) => self,
|
||||
@@ -6033,7 +6051,7 @@ impl<'db> Type<'db> {
|
||||
| Type::DataclassDecorator(_)
|
||||
| Type::DataclassTransformer(_)
|
||||
| Type::ModuleLiteral(_)
|
||||
| Type::ClassLiteral(_)
|
||||
| Type::ClassSingleton(_)
|
||||
| Type::IntLiteral(_)
|
||||
| Type::BooleanLiteral(_)
|
||||
| Type::LiteralString
|
||||
@@ -6114,8 +6132,8 @@ impl<'db> Type<'db> {
|
||||
Some(TypeDefinition::Function(function.definition(db)))
|
||||
}
|
||||
Self::ModuleLiteral(module) => Some(TypeDefinition::Module(module.module(db))),
|
||||
Self::ClassLiteral(class_literal) => {
|
||||
Some(TypeDefinition::Class(class_literal.definition(db)))
|
||||
Self::ClassSingleton(singleton) => {
|
||||
Some(TypeDefinition::Class(singleton.definition(db)))
|
||||
}
|
||||
Self::GenericAlias(alias) => Some(TypeDefinition::Class(alias.definition(db))),
|
||||
Self::NominalInstance(instance) => {
|
||||
@@ -6239,7 +6257,7 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn generic_origin(self, db: &'db dyn Db) -> Option<ClassLiteral<'db>> {
|
||||
pub(crate) fn generic_origin(self, db: &'db dyn Db) -> Option<ClassSingleton<'db>> {
|
||||
match self {
|
||||
Type::GenericAlias(generic) => Some(generic.origin(db)),
|
||||
Type::NominalInstance(instance) => {
|
||||
@@ -6448,7 +6466,7 @@ impl<'db> KnownInstanceType<'db> {
|
||||
}
|
||||
|
||||
fn to_meta_type(self, db: &'db dyn Db) -> Type<'db> {
|
||||
self.class().to_class_literal(db)
|
||||
self.class().to_class_singleton(db)
|
||||
}
|
||||
|
||||
/// Return the instance type which this type is a subtype of.
|
||||
@@ -8997,7 +9015,7 @@ impl<'db> TypeAliasType<'db> {
|
||||
#[derive(Debug, Clone, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
|
||||
pub(super) struct MetaclassCandidate<'db> {
|
||||
metaclass: ClassType<'db>,
|
||||
explicit_metaclass_of: ClassLiteral<'db>,
|
||||
explicit_metaclass_of: ClassSingleton<'db>,
|
||||
}
|
||||
|
||||
#[salsa::interned(debug, heap_size=ruff_memory_usage::heap_size)]
|
||||
@@ -9479,7 +9497,7 @@ impl<'db> BytesLiteralType<'db> {
|
||||
#[derive(PartialOrd, Ord)]
|
||||
pub struct EnumLiteralType<'db> {
|
||||
/// A reference to the enum class this literal belongs to
|
||||
enum_class: ClassLiteral<'db>,
|
||||
enum_class: ClassSingleton<'db>,
|
||||
/// The name of the enum member
|
||||
#[returns(ref)]
|
||||
name: Name,
|
||||
@@ -9505,8 +9523,8 @@ pub struct TypedDictType<'db> {
|
||||
|
||||
impl<'db> TypedDictType<'db> {
|
||||
pub(crate) fn items(self, db: &'db dyn Db) -> FxOrderMap<Name, Field<'db>> {
|
||||
let (class_literal, specialization) = self.defining_class.class_literal(db);
|
||||
class_literal.fields(db, specialization, CodeGeneratorKind::TypedDict)
|
||||
let (singleton, specialization) = self.defining_class.class_singleton(db);
|
||||
singleton.fields(db, specialization, CodeGeneratorKind::TypedDict)
|
||||
}
|
||||
|
||||
pub(crate) fn apply_type_mapping_impl<'a>(
|
||||
@@ -9628,8 +9646,8 @@ impl<'db> SuperOwnerKind<'db> {
|
||||
fn try_from_type(db: &'db dyn Db, ty: Type<'db>) -> Option<Self> {
|
||||
match ty {
|
||||
Type::Dynamic(dynamic) => Some(SuperOwnerKind::Dynamic(dynamic)),
|
||||
Type::ClassLiteral(class_literal) => Some(SuperOwnerKind::Class(
|
||||
class_literal.apply_optional_specialization(db, None),
|
||||
Type::ClassSingleton(singleton) => Some(SuperOwnerKind::Class(
|
||||
singleton.apply_optional_specialization(db, None),
|
||||
)),
|
||||
Type::NominalInstance(instance) => Some(SuperOwnerKind::Instance(instance)),
|
||||
Type::BooleanLiteral(_) => {
|
||||
@@ -9714,7 +9732,7 @@ impl<'db> BoundSuperType<'db> {
|
||||
// - There are objects that are not valid in a class's bases list
|
||||
// but are valid as pivot classes, e.g. unsubscripted `typing.Generic`
|
||||
let pivot_class = match pivot_class_type {
|
||||
Type::ClassLiteral(class) => ClassBase::Class(ClassType::NonGeneric(class)),
|
||||
Type::ClassSingleton(class) => ClassBase::Class(ClassType::NonGeneric(class)),
|
||||
Type::GenericAlias(class) => ClassBase::Class(ClassType::Generic(class)),
|
||||
Type::SubclassOf(subclass_of) if subclass_of.subclass_of().is_dynamic() => {
|
||||
ClassBase::Dynamic(
|
||||
@@ -9844,7 +9862,7 @@ impl<'db> BoundSuperType<'db> {
|
||||
SuperOwnerKind::Instance(instance) => instance.class(db),
|
||||
};
|
||||
|
||||
let (class_literal, _) = class.class_literal(db);
|
||||
let (singleton, _) = class.class_singleton(db);
|
||||
// TODO properly support super() with generic types
|
||||
// * requires a fix for https://github.com/astral-sh/ruff/issues/17432
|
||||
// * also requires understanding how we should handle cases like this:
|
||||
@@ -9855,9 +9873,9 @@ impl<'db> BoundSuperType<'db> {
|
||||
// super(B, b_int)
|
||||
// super(B[int], b_unknown)
|
||||
// ```
|
||||
match class_literal.generic_context(db) {
|
||||
match singleton.generic_context(db) {
|
||||
Some(_) => Place::bound(todo_type!("super in generic class")).into(),
|
||||
None => class_literal.class_member_from_mro(
|
||||
None => singleton.class_member_from_mro(
|
||||
db,
|
||||
name,
|
||||
policy,
|
||||
|
||||
@@ -577,7 +577,7 @@ impl<'db> IntersectionBuilder<'db> {
|
||||
self
|
||||
}
|
||||
Type::NominalInstance(instance)
|
||||
if enum_metadata(self.db, instance.class(self.db).class_literal(self.db).0)
|
||||
if enum_metadata(self.db, instance.class(self.db).class_singleton(self.db).0)
|
||||
.is_some() =>
|
||||
{
|
||||
let mut contains_enum_literal_as_negative_element = false;
|
||||
@@ -602,7 +602,7 @@ impl<'db> IntersectionBuilder<'db> {
|
||||
let db = self.db;
|
||||
self.add_positive(Type::Union(UnionType::new(
|
||||
db,
|
||||
enum_member_literals(db, instance.class(db).class_literal(db).0, None)
|
||||
enum_member_literals(db, instance.class(db).class_singleton(db).0, None)
|
||||
.expect("Calling `enum_member_literals` on an enum class")
|
||||
.collect::<Box<[_]>>(),
|
||||
)))
|
||||
@@ -1175,7 +1175,7 @@ mod tests {
|
||||
.ignore_possibly_unbound()
|
||||
.unwrap();
|
||||
|
||||
let literals = enum_member_literals(&db, safe_uuid_class.expect_class_literal(), None)
|
||||
let literals = enum_member_literals(&db, safe_uuid_class.expect_class_singleton(), None)
|
||||
.unwrap()
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(literals.len(), 3);
|
||||
|
||||
@@ -251,7 +251,8 @@ fn expand_type<'db>(db: &'db dyn Db, ty: Type<'db>) -> Option<Vec<Type<'db>>> {
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(enum_members) = enum_member_literals(db, class.class_literal(db).0, None) {
|
||||
if let Some(enum_members) = enum_member_literals(db, class.class_singleton(db).0, None)
|
||||
{
|
||||
return Some(enum_members.collect());
|
||||
}
|
||||
|
||||
|
||||
@@ -644,7 +644,7 @@ impl<'db> Bindings<'db> {
|
||||
// TODO: Handle generic functions, and unions/intersections of
|
||||
// generic types
|
||||
overload.set_return_type(match ty {
|
||||
Type::ClassLiteral(class) => class
|
||||
Type::ClassSingleton(class) => class
|
||||
.generic_context(db)
|
||||
.map(|generic_context| generic_context.as_tuple(db))
|
||||
.unwrap_or_else(|| Type::none(db)),
|
||||
@@ -693,7 +693,7 @@ impl<'db> Bindings<'db> {
|
||||
Some(KnownFunction::EnumMembers) => {
|
||||
if let [Some(ty)] = overload.parameter_types() {
|
||||
let return_ty = match ty {
|
||||
Type::ClassLiteral(class) => {
|
||||
Type::ClassSingleton(class) => {
|
||||
if let Some(metadata) = enums::enum_metadata(db, *class) {
|
||||
Type::heterogeneous_tuple(
|
||||
db,
|
||||
@@ -760,14 +760,15 @@ impl<'db> Bindings<'db> {
|
||||
Some(KnownFunction::IsProtocol) => {
|
||||
if let [Some(ty)] = overload.parameter_types() {
|
||||
overload.set_return_type(Type::BooleanLiteral(
|
||||
ty.into_class_literal()
|
||||
ty.into_class_singleton()
|
||||
.is_some_and(|class| class.is_protocol(db)),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Some(KnownFunction::GetProtocolMembers) => {
|
||||
if let [Some(Type::ClassLiteral(class))] = overload.parameter_types() {
|
||||
if let [Some(Type::ClassSingleton(class))] = overload.parameter_types()
|
||||
{
|
||||
if let Some(protocol_class) = class.into_protocol_class(db) {
|
||||
let member_names = protocol_class
|
||||
.interface(db)
|
||||
@@ -878,7 +879,7 @@ impl<'db> Bindings<'db> {
|
||||
}
|
||||
|
||||
// `dataclass` being used as a non-decorator
|
||||
if let [Some(Type::ClassLiteral(class_literal))] =
|
||||
if let [Some(Type::ClassSingleton(class_literal))] =
|
||||
overload.parameter_types()
|
||||
{
|
||||
let params = DataclassParams::default();
|
||||
@@ -1008,7 +1009,7 @@ impl<'db> Bindings<'db> {
|
||||
}
|
||||
},
|
||||
|
||||
Type::ClassLiteral(class) => match class.known(db) {
|
||||
Type::ClassSingleton(class) => match class.known(db) {
|
||||
Some(KnownClass::Bool) => match overload.parameter_types() {
|
||||
[Some(arg)] => overload.set_return_type(arg.bool(db).into_type(db)),
|
||||
[None] => overload.set_return_type(Type::BooleanLiteral(false)),
|
||||
@@ -1056,6 +1057,22 @@ impl<'db> Bindings<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
Some(KnownClass::NewType) => match overload.parameter_types() {
|
||||
[Some(Type::StringLiteral(name)), Some(supertype)] => {
|
||||
let params = DataclassParams::default();
|
||||
overload.set_return_type(Type::from(ClassLiteral::new(
|
||||
db,
|
||||
ast::name::Name::new(name.value(db)),
|
||||
what_goes_here,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)));
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
|
||||
_ => {}
|
||||
},
|
||||
|
||||
@@ -2560,7 +2577,7 @@ impl<'db> CallableDescription<'db> {
|
||||
kind: "function",
|
||||
name: function.name(db),
|
||||
}),
|
||||
Type::ClassLiteral(class_type) => Some(CallableDescription {
|
||||
Type::ClassSingleton(class_type) => Some(CallableDescription {
|
||||
kind: "class",
|
||||
name: class_type.name(db),
|
||||
}),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -62,7 +62,7 @@ impl<'db> ClassBase<'db> {
|
||||
/// Return a `ClassBase` representing the class `builtins.object`
|
||||
pub(super) fn object(db: &'db dyn Db) -> Self {
|
||||
KnownClass::Object
|
||||
.to_class_literal(db)
|
||||
.to_class_singleton(db)
|
||||
.to_class_type(db)
|
||||
.map_or(Self::unknown(), Self::Class)
|
||||
}
|
||||
@@ -77,7 +77,7 @@ impl<'db> ClassBase<'db> {
|
||||
) -> Option<Self> {
|
||||
match ty {
|
||||
Type::Dynamic(dynamic) => Some(Self::Dynamic(dynamic)),
|
||||
Type::ClassLiteral(literal) => {
|
||||
Type::ClassSingleton(literal) => {
|
||||
if literal.is_known(db, KnownClass::Any) {
|
||||
Some(Self::Dynamic(DynamicType::Any))
|
||||
} else {
|
||||
@@ -220,38 +220,42 @@ impl<'db> ClassBase<'db> {
|
||||
|
||||
// TODO: Classes inheriting from `typing.Type` et al. also have `Generic` in their MRO
|
||||
SpecialFormType::Dict => {
|
||||
Self::try_from_type(db, KnownClass::Dict.to_class_literal(db), subclass)
|
||||
Self::try_from_type(db, KnownClass::Dict.to_class_singleton(db), subclass)
|
||||
}
|
||||
SpecialFormType::List => {
|
||||
Self::try_from_type(db, KnownClass::List.to_class_literal(db), subclass)
|
||||
Self::try_from_type(db, KnownClass::List.to_class_singleton(db), subclass)
|
||||
}
|
||||
SpecialFormType::Type => {
|
||||
Self::try_from_type(db, KnownClass::Type.to_class_literal(db), subclass)
|
||||
Self::try_from_type(db, KnownClass::Type.to_class_singleton(db), subclass)
|
||||
}
|
||||
SpecialFormType::Tuple => {
|
||||
Self::try_from_type(db, KnownClass::Tuple.to_class_literal(db), subclass)
|
||||
Self::try_from_type(db, KnownClass::Tuple.to_class_singleton(db), subclass)
|
||||
}
|
||||
SpecialFormType::Set => {
|
||||
Self::try_from_type(db, KnownClass::Set.to_class_literal(db), subclass)
|
||||
Self::try_from_type(db, KnownClass::Set.to_class_singleton(db), subclass)
|
||||
}
|
||||
SpecialFormType::FrozenSet => {
|
||||
Self::try_from_type(db, KnownClass::FrozenSet.to_class_literal(db), subclass)
|
||||
Self::try_from_type(db, KnownClass::FrozenSet.to_class_singleton(db), subclass)
|
||||
}
|
||||
SpecialFormType::ChainMap => {
|
||||
Self::try_from_type(db, KnownClass::ChainMap.to_class_literal(db), subclass)
|
||||
Self::try_from_type(db, KnownClass::ChainMap.to_class_singleton(db), subclass)
|
||||
}
|
||||
SpecialFormType::Counter => {
|
||||
Self::try_from_type(db, KnownClass::Counter.to_class_literal(db), subclass)
|
||||
}
|
||||
SpecialFormType::DefaultDict => {
|
||||
Self::try_from_type(db, KnownClass::DefaultDict.to_class_literal(db), subclass)
|
||||
Self::try_from_type(db, KnownClass::Counter.to_class_singleton(db), subclass)
|
||||
}
|
||||
SpecialFormType::DefaultDict => Self::try_from_type(
|
||||
db,
|
||||
KnownClass::DefaultDict.to_class_singleton(db),
|
||||
subclass,
|
||||
),
|
||||
SpecialFormType::Deque => {
|
||||
Self::try_from_type(db, KnownClass::Deque.to_class_literal(db), subclass)
|
||||
}
|
||||
SpecialFormType::OrderedDict => {
|
||||
Self::try_from_type(db, KnownClass::OrderedDict.to_class_literal(db), subclass)
|
||||
Self::try_from_type(db, KnownClass::Deque.to_class_singleton(db), subclass)
|
||||
}
|
||||
SpecialFormType::OrderedDict => Self::try_from_type(
|
||||
db,
|
||||
KnownClass::OrderedDict.to_class_singleton(db),
|
||||
subclass,
|
||||
),
|
||||
SpecialFormType::TypedDict => Some(Self::TypedDict),
|
||||
SpecialFormType::Callable => Self::try_from_type(
|
||||
db,
|
||||
@@ -302,7 +306,7 @@ impl<'db> ClassBase<'db> {
|
||||
pub(super) fn has_cyclic_mro(self, db: &'db dyn Db) -> bool {
|
||||
match self {
|
||||
ClassBase::Class(class) => {
|
||||
let (class_literal, specialization) = class.class_literal(db);
|
||||
let (class_literal, specialization) = class.class_singleton(db);
|
||||
class_literal
|
||||
.try_mro(db, specialization)
|
||||
.is_err_and(MroError::is_cycle)
|
||||
|
||||
@@ -1848,7 +1848,7 @@ fn report_invalid_assignment_with_message(
|
||||
return;
|
||||
};
|
||||
match target_ty {
|
||||
Type::ClassLiteral(class) => {
|
||||
Type::ClassSingleton(class) => {
|
||||
let mut diag = builder.into_diagnostic(format_args!(
|
||||
"Implicit shadowing of class `{}`",
|
||||
class.name(context.db()),
|
||||
@@ -2357,7 +2357,7 @@ pub(crate) fn report_bad_argument_to_protocol_interface(
|
||||
),
|
||||
);
|
||||
class_def_diagnostic.annotate(Annotation::primary(
|
||||
class.class_literal(db).0.header_span(db),
|
||||
class.class_singleton(db).0.header_span(db),
|
||||
));
|
||||
diagnostic.sub(class_def_diagnostic);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ impl Display for DisplayType<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
let representation = self.ty.representation(self.db);
|
||||
match self.ty {
|
||||
Type::ClassLiteral(literal) if literal.is_known(self.db, KnownClass::Any) => {
|
||||
Type::ClassSingleton(literal) if literal.is_known(self.db, KnownClass::Any) => {
|
||||
write!(f, "typing.Any")
|
||||
}
|
||||
Type::IntLiteral(_)
|
||||
@@ -111,7 +111,7 @@ impl Display for DisplayRepresentation<'_> {
|
||||
Type::ModuleLiteral(module) => {
|
||||
write!(f, "<module '{}'>", module.module(self.db).name(self.db))
|
||||
}
|
||||
Type::ClassLiteral(class) => {
|
||||
Type::ClassSingleton(class) => {
|
||||
write!(f, "<class '{}'>", class.name(self.db))
|
||||
}
|
||||
Type::GenericAlias(generic) => write!(f, "<class '{}'>", generic.display(self.db)),
|
||||
|
||||
@@ -66,7 +66,7 @@ pub(crate) fn enum_metadata<'db>(
|
||||
return None;
|
||||
}
|
||||
|
||||
if !Type::ClassLiteral(class).is_subtype_of(db, KnownClass::Enum.to_subclass_of(db))
|
||||
if !Type::ClassSingleton(class).is_subtype_of(db, KnownClass::Enum.to_subclass_of(db))
|
||||
&& !class
|
||||
.metaclass(db)
|
||||
.is_subtype_of(db, KnownClass::EnumType.to_subclass_of(db))
|
||||
@@ -249,7 +249,7 @@ pub(crate) fn is_single_member_enum<'db>(db: &'db dyn Db, class: ClassLiteral<'d
|
||||
|
||||
pub(crate) fn is_enum_class<'db>(db: &'db dyn Db, ty: Type<'db>) -> bool {
|
||||
match ty {
|
||||
Type::ClassLiteral(class_literal) => enum_metadata(db, class_literal).is_some(),
|
||||
Type::ClassSingleton(class_literal) => enum_metadata(db, class_literal).is_some(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ impl FunctionDecorators {
|
||||
Some(KnownFunction::Override) => FunctionDecorators::OVERRIDE,
|
||||
_ => FunctionDecorators::empty(),
|
||||
},
|
||||
Type::ClassLiteral(class) => match class.known(db) {
|
||||
Type::ClassSingleton(class) => match class.known(db) {
|
||||
Some(KnownClass::Classmethod) => FunctionDecorators::CLASSMETHOD,
|
||||
Some(KnownClass::Staticmethod) => FunctionDecorators::STATICMETHOD,
|
||||
_ => FunctionDecorators::empty(),
|
||||
@@ -997,7 +997,7 @@ fn is_instance_truthiness<'db>(
|
||||
always_true_if(is_instance(&KnownClass::FunctionType.to_instance(db)))
|
||||
}
|
||||
|
||||
Type::ClassLiteral(..) => always_true_if(is_instance(&KnownClass::Type.to_instance(db))),
|
||||
Type::ClassSingleton(..) => always_true_if(is_instance(&KnownClass::Type.to_instance(db))),
|
||||
|
||||
Type::TypeAlias(alias) => is_instance_truthiness(db, alias.value_type(db), class),
|
||||
|
||||
@@ -1414,7 +1414,7 @@ impl KnownFunction {
|
||||
}
|
||||
|
||||
KnownFunction::GetProtocolMembers => {
|
||||
let [Some(Type::ClassLiteral(class))] = parameter_types else {
|
||||
let [Some(Type::ClassSingleton(class))] = parameter_types else {
|
||||
return;
|
||||
};
|
||||
if class.is_protocol(db) {
|
||||
@@ -1428,7 +1428,7 @@ impl KnownFunction {
|
||||
return;
|
||||
};
|
||||
let Some(protocol_class) = param_type
|
||||
.into_class_literal()
|
||||
.into_class_singleton()
|
||||
.and_then(|class| class.into_protocol_class(db))
|
||||
else {
|
||||
report_bad_argument_to_protocol_interface(
|
||||
@@ -1451,7 +1451,7 @@ impl KnownFunction {
|
||||
}
|
||||
|
||||
KnownFunction::IsInstance | KnownFunction::IsSubclass => {
|
||||
let [Some(first_arg), Some(Type::ClassLiteral(class))] = parameter_types else {
|
||||
let [Some(first_arg), Some(Type::ClassSingleton(class))] = parameter_types else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ fn enclosing_generic_contexts<'db>(
|
||||
NodeWithScopeKind::Class(class) => {
|
||||
let definition = index.expect_single_definition(class.node(module));
|
||||
binding_type(db, definition)
|
||||
.into_class_literal()?
|
||||
.into_class_singleton()?
|
||||
.generic_context(db)
|
||||
}
|
||||
NodeWithScopeKind::Function(function) => {
|
||||
|
||||
@@ -95,26 +95,26 @@ impl<'db> AllMembers<'db> {
|
||||
),
|
||||
|
||||
Type::NominalInstance(instance) => {
|
||||
let (class_literal, _specialization) = instance.class(db).class_literal(db);
|
||||
let (class_literal, _specialization) = instance.class(db).class_singleton(db);
|
||||
self.extend_with_instance_members(db, ty, class_literal);
|
||||
}
|
||||
|
||||
Type::ClassLiteral(class_literal) if class_literal.is_typed_dict(db) => {
|
||||
self.extend_with_type(db, KnownClass::TypedDictFallback.to_class_literal(db));
|
||||
Type::ClassSingleton(class_literal) if class_literal.is_typed_dict(db) => {
|
||||
self.extend_with_type(db, KnownClass::TypedDictFallback.to_class_singleton(db));
|
||||
}
|
||||
|
||||
Type::GenericAlias(generic_alias) if generic_alias.is_typed_dict(db) => {
|
||||
self.extend_with_type(db, KnownClass::TypedDictFallback.to_class_literal(db));
|
||||
self.extend_with_type(db, KnownClass::TypedDictFallback.to_class_singleton(db));
|
||||
}
|
||||
|
||||
Type::SubclassOf(subclass_of_type) if subclass_of_type.is_typed_dict(db) => {
|
||||
self.extend_with_type(db, KnownClass::TypedDictFallback.to_class_literal(db));
|
||||
self.extend_with_type(db, KnownClass::TypedDictFallback.to_class_singleton(db));
|
||||
}
|
||||
|
||||
Type::ClassLiteral(class_literal) => {
|
||||
Type::ClassSingleton(class_literal) => {
|
||||
self.extend_with_class_members(db, ty, class_literal);
|
||||
|
||||
if let Type::ClassLiteral(meta_class_literal) = ty.to_meta_type(db) {
|
||||
if let Type::ClassSingleton(meta_class_literal) = ty.to_meta_type(db) {
|
||||
self.extend_with_class_members(db, ty, meta_class_literal);
|
||||
}
|
||||
}
|
||||
@@ -126,7 +126,7 @@ impl<'db> AllMembers<'db> {
|
||||
|
||||
Type::SubclassOf(subclass_of_type) => {
|
||||
if let Some(class_literal) = subclass_of_type.subclass_of().into_class() {
|
||||
self.extend_with_class_members(db, ty, class_literal.class_literal(db).0);
|
||||
self.extend_with_class_members(db, ty, class_literal.class_singleton(db).0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,12 +155,12 @@ impl<'db> AllMembers<'db> {
|
||||
| Type::TypeVar(_)
|
||||
| Type::BoundSuper(_)
|
||||
| Type::TypeIs(_) => match ty.to_meta_type(db) {
|
||||
Type::ClassLiteral(class_literal) => {
|
||||
Type::ClassSingleton(class_literal) => {
|
||||
self.extend_with_class_members(db, ty, class_literal);
|
||||
}
|
||||
Type::SubclassOf(subclass_of) => {
|
||||
if let Some(class) = subclass_of.subclass_of().into_class() {
|
||||
self.extend_with_class_members(db, ty, class.class_literal(db).0);
|
||||
self.extend_with_class_members(db, ty, class.class_singleton(db).0);
|
||||
}
|
||||
}
|
||||
Type::GenericAlias(generic_alias) => {
|
||||
@@ -171,12 +171,12 @@ impl<'db> AllMembers<'db> {
|
||||
},
|
||||
|
||||
Type::TypedDict(_) => {
|
||||
if let Type::ClassLiteral(class_literal) = ty.to_meta_type(db) {
|
||||
if let Type::ClassSingleton(class_literal) = ty.to_meta_type(db) {
|
||||
self.extend_with_class_members(db, ty, class_literal);
|
||||
}
|
||||
|
||||
if let Type::ClassLiteral(class) =
|
||||
KnownClass::TypedDictFallback.to_class_literal(db)
|
||||
if let Type::ClassSingleton(class) =
|
||||
KnownClass::TypedDictFallback.to_class_singleton(db)
|
||||
{
|
||||
self.extend_with_instance_members(db, ty, class);
|
||||
}
|
||||
@@ -222,7 +222,7 @@ impl<'db> AllMembers<'db> {
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Type::ClassLiteral(class) if class.is_protocol(db) => continue,
|
||||
Type::ClassSingleton(class) if class.is_protocol(db) => continue,
|
||||
Type::KnownInstance(
|
||||
KnownInstanceType::TypeVar(_) | KnownInstanceType::TypeAliasType(_),
|
||||
) => continue,
|
||||
@@ -279,7 +279,7 @@ impl<'db> AllMembers<'db> {
|
||||
for parent in class_literal
|
||||
.iter_mro(db, None)
|
||||
.filter_map(ClassBase::into_class)
|
||||
.map(|class| class.class_literal(db).0)
|
||||
.map(|class| class.class_singleton(db).0)
|
||||
{
|
||||
let parent_scope = parent.body_scope(db);
|
||||
for Member { name, .. } in all_declarations_and_bindings(db, parent_scope) {
|
||||
@@ -301,7 +301,7 @@ impl<'db> AllMembers<'db> {
|
||||
for parent in class_literal
|
||||
.iter_mro(db, None)
|
||||
.filter_map(ClassBase::into_class)
|
||||
.map(|class| class.class_literal(db).0)
|
||||
.map(|class| class.class_singleton(db).0)
|
||||
{
|
||||
let class_body_scope = parent.body_scope(db);
|
||||
let file = class_body_scope.file(db);
|
||||
@@ -605,13 +605,13 @@ pub fn definitions_for_attribute<'db>(
|
||||
|
||||
// First, transform the type to its meta type, unless it's already a class-like type.
|
||||
let meta_type = match ty {
|
||||
Type::ClassLiteral(_) | Type::SubclassOf(_) | Type::GenericAlias(_) => ty,
|
||||
Type::ClassSingleton(_) | Type::SubclassOf(_) | Type::GenericAlias(_) => ty,
|
||||
_ => ty.to_meta_type(db),
|
||||
};
|
||||
let class_literal = match meta_type {
|
||||
Type::ClassLiteral(class_literal) => class_literal,
|
||||
Type::ClassSingleton(class_literal) => class_literal,
|
||||
Type::SubclassOf(subclass) => match subclass.subclass_of().into_class() {
|
||||
Some(cls) => cls.class_literal(db).0,
|
||||
Some(cls) => cls.class_singleton(db).0,
|
||||
None => continue,
|
||||
},
|
||||
_ => continue,
|
||||
@@ -621,7 +621,7 @@ pub fn definitions_for_attribute<'db>(
|
||||
'scopes: for ancestor in class_literal
|
||||
.iter_mro(db, None)
|
||||
.filter_map(ClassBase::into_class)
|
||||
.map(|cls| cls.class_literal(db).0)
|
||||
.map(|cls| cls.class_singleton(db).0)
|
||||
{
|
||||
let class_scope = ancestor.body_scope(db);
|
||||
let class_place_table = crate::semantic_index::place_table(db, class_scope);
|
||||
|
||||
@@ -384,7 +384,7 @@ pub(crate) fn nearest_enclosing_class<'db>(
|
||||
infer_definition_types(db, definition)
|
||||
.declaration_type(definition)
|
||||
.inner_type()
|
||||
.into_class_literal()
|
||||
.into_class_singleton()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1083,7 +1083,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
// Filter out class literals that result from imports
|
||||
if let DefinitionKind::Class(class) = definition.kind(self.db()) {
|
||||
ty.inner_type()
|
||||
.into_class_literal()
|
||||
.into_class_singleton()
|
||||
.map(|class_literal| (class_literal, class.node(self.module())))
|
||||
} else {
|
||||
None
|
||||
@@ -1169,17 +1169,20 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
);
|
||||
continue;
|
||||
}
|
||||
Type::ClassLiteral(class) => ClassType::NonGeneric(*class),
|
||||
Type::ClassSingleton(class) => ClassType::NonGeneric(*class),
|
||||
Type::GenericAlias(class) => ClassType::Generic(*class),
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
if let Some(solid_base) = base_class.nearest_solid_base(self.db()) {
|
||||
solid_bases.insert(solid_base, i, base_class.class_literal(self.db()).0);
|
||||
solid_bases.insert(solid_base, i, base_class.class_singleton(self.db()).0);
|
||||
}
|
||||
|
||||
if is_protocol
|
||||
&& !(base_class.class_literal(self.db()).0.is_protocol(self.db())
|
||||
&& !(base_class
|
||||
.class_singleton(self.db())
|
||||
.0
|
||||
.is_protocol(self.db())
|
||||
|| base_class.is_known(self.db(), KnownClass::Object))
|
||||
{
|
||||
if let Some(builder) = self
|
||||
@@ -1521,7 +1524,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
self.index
|
||||
.expect_single_definition(class_node_ref.node(self.module())),
|
||||
)
|
||||
.expect_class_literal();
|
||||
.expect_class_singleton();
|
||||
|
||||
if class.is_protocol(self.db())
|
||||
|| (class.is_abstract(self.db())
|
||||
@@ -2358,7 +2361,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
|
||||
let class_stmt = class_scope.node().as_class(self.module())?;
|
||||
let class_definition = self.index.expect_single_definition(class_stmt);
|
||||
binding_type(self.db(), class_definition).into_class_literal()
|
||||
binding_type(self.db(), class_definition).into_class_singleton()
|
||||
}
|
||||
|
||||
/// If the current scope is a (non-lambda) function, return that function's AST node.
|
||||
@@ -4277,7 +4280,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
}
|
||||
}
|
||||
|
||||
Type::ClassLiteral(..) | Type::GenericAlias(..) | Type::SubclassOf(..) => {
|
||||
Type::ClassSingleton(..) | Type::GenericAlias(..) | Type::SubclassOf(..) => {
|
||||
match object_ty.class_member(db, attribute.into()) {
|
||||
PlaceAndQualifiers {
|
||||
place: Place::Type(meta_attr_ty, meta_attr_boundness),
|
||||
@@ -6186,7 +6189,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
}
|
||||
|
||||
let class = match callable_type {
|
||||
Type::ClassLiteral(class) => Some(ClassType::NonGeneric(class)),
|
||||
Type::ClassSingleton(class) => Some(ClassType::NonGeneric(class)),
|
||||
Type::GenericAlias(generic) => Some(ClassType::Generic(generic)),
|
||||
Type::SubclassOf(subclass) => subclass.subclass_of().into_class(),
|
||||
_ => None,
|
||||
@@ -6202,7 +6205,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
// <https://typing.python.org/en/latest/spec/protocol.html#type-and-class-objects-vs-protocols>.
|
||||
if !callable_type.is_subclass_of() {
|
||||
if let Some(protocol) = class
|
||||
.class_literal(self.db())
|
||||
.class_singleton(self.db())
|
||||
.0
|
||||
.into_protocol_class(self.db())
|
||||
{
|
||||
@@ -6231,6 +6234,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
| KnownClass::TypeVar
|
||||
| KnownClass::TypeAliasType
|
||||
| KnownClass::Deprecated
|
||||
| KnownClass::NewType
|
||||
)
|
||||
) || (
|
||||
// Constructor calls to `tuple` and subclasses of `tuple` are handled in `Type::Bindings`,
|
||||
@@ -6244,7 +6248,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
// until we support the functional syntax for creating enum classes
|
||||
if !has_special_cased_constructor
|
||||
&& KnownClass::Enum
|
||||
.to_class_literal(self.db())
|
||||
.to_class_singleton(self.db())
|
||||
.to_class_type(self.db())
|
||||
.is_none_or(|enum_class| !class.is_subclass_of(self.db(), enum_class))
|
||||
{
|
||||
@@ -6288,7 +6292,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
);
|
||||
}
|
||||
}
|
||||
Type::ClassLiteral(class) => {
|
||||
Type::ClassSingleton(class) => {
|
||||
if let Some(known_class) = class.known(self.db()) {
|
||||
known_class.check_call(
|
||||
&self.context,
|
||||
@@ -6489,7 +6493,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
/// Check if the given ty is `@deprecated` or not
|
||||
fn check_deprecated<T: Ranged>(&self, ranged: T, ty: Type) {
|
||||
// First handle classes
|
||||
if let Type::ClassLiteral(class_literal) = ty {
|
||||
if let Type::ClassSingleton(class_literal) = ty {
|
||||
let Some(deprecated) = class_literal.deprecated(self.db()) else {
|
||||
return;
|
||||
};
|
||||
@@ -7087,7 +7091,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
|
||||
if report_unresolved_attribute {
|
||||
let bound_on_instance = match value_type {
|
||||
Type::ClassLiteral(class) => {
|
||||
Type::ClassSingleton(class) => {
|
||||
!class.instance_member(db, None, attr).place.is_unbound()
|
||||
}
|
||||
Type::SubclassOf(subclass_of @ SubclassOfType { .. }) => {
|
||||
@@ -7231,7 +7235,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
| Type::DataclassTransformer(_)
|
||||
| Type::BoundMethod(_)
|
||||
| Type::ModuleLiteral(_)
|
||||
| Type::ClassLiteral(_)
|
||||
| Type::ClassSingleton(_)
|
||||
| Type::GenericAlias(_)
|
||||
| Type::SubclassOf(_)
|
||||
| Type::NominalInstance(_)
|
||||
@@ -7573,7 +7577,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
| Type::DataclassDecorator(_)
|
||||
| Type::DataclassTransformer(_)
|
||||
| Type::ModuleLiteral(_)
|
||||
| Type::ClassLiteral(_)
|
||||
| Type::ClassSingleton(_)
|
||||
| Type::GenericAlias(_)
|
||||
| Type::SubclassOf(_)
|
||||
| Type::NominalInstance(_)
|
||||
@@ -7603,7 +7607,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
| Type::DataclassDecorator(_)
|
||||
| Type::DataclassTransformer(_)
|
||||
| Type::ModuleLiteral(_)
|
||||
| Type::ClassLiteral(_)
|
||||
| Type::ClassSingleton(_)
|
||||
| Type::GenericAlias(_)
|
||||
| Type::SubclassOf(_)
|
||||
| Type::NominalInstance(_)
|
||||
@@ -8635,7 +8639,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
// this callable as the `__class_getitem__` method on `type`. That probably requires
|
||||
// updating all of the subscript logic below to use custom callables for all of the _other_
|
||||
// special cases, too.
|
||||
if let Type::ClassLiteral(class) = value_ty {
|
||||
if let Type::ClassSingleton(class) = value_ty {
|
||||
if class.is_tuple(self.db()) {
|
||||
return tuple_generic_alias(self.db(), self.infer_tuple_type_expression(slice));
|
||||
}
|
||||
@@ -9032,7 +9036,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Type::ClassLiteral(class) = value_ty {
|
||||
if let Type::ClassSingleton(class) = value_ty {
|
||||
if class.is_known(db, KnownClass::Type) {
|
||||
return KnownClass::GenericAlias.to_instance(db);
|
||||
}
|
||||
@@ -9051,7 +9055,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
|
||||
// TODO: properly handle old-style generics; get rid of this temporary hack
|
||||
if !value_ty
|
||||
.into_class_literal()
|
||||
.into_class_singleton()
|
||||
.is_some_and(|class| class.iter_mro(db, None).contains(&ClassBase::Generic))
|
||||
{
|
||||
report_non_subscriptable(context, value_node.into(), value_ty, "__class_getitem__");
|
||||
@@ -9418,7 +9422,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
Type::SpecialForm(SpecialFormType::Final) => {
|
||||
TypeAndQualifiers::new(Type::unknown(), TypeQualifiers::FINAL)
|
||||
}
|
||||
Type::ClassLiteral(class)
|
||||
Type::ClassSingleton(class)
|
||||
if class.is_known(self.db(), KnownClass::InitVar) =>
|
||||
{
|
||||
if let Some(builder) =
|
||||
@@ -9534,7 +9538,9 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
}
|
||||
type_and_qualifiers
|
||||
}
|
||||
Type::ClassLiteral(class) if class.is_known(self.db(), KnownClass::InitVar) => {
|
||||
Type::ClassSingleton(class)
|
||||
if class.is_known(self.db(), KnownClass::InitVar) =>
|
||||
{
|
||||
let arguments = if let ast::Expr::Tuple(tuple) = slice {
|
||||
&*tuple.elts
|
||||
} else {
|
||||
@@ -10069,7 +10075,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
value_ty: Type<'db>,
|
||||
) -> Type<'db> {
|
||||
match value_ty {
|
||||
Type::ClassLiteral(class_literal) => match class_literal.known(self.db()) {
|
||||
Type::ClassSingleton(class_literal) => match class_literal.known(self.db()) {
|
||||
Some(KnownClass::Tuple) => Type::tuple(self.infer_tuple_type_expression(slice)),
|
||||
Some(KnownClass::Type) => self.infer_subclass_of_type_expression(slice),
|
||||
_ => self.infer_subscript_type_expression(subscript, value_ty),
|
||||
@@ -10195,7 +10201,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
ast::Expr::Name(_) | ast::Expr::Attribute(_) => {
|
||||
let name_ty = self.infer_expression(slice);
|
||||
match name_ty {
|
||||
Type::ClassLiteral(class_literal) => {
|
||||
Type::ClassSingleton(class_literal) => {
|
||||
if class_literal.is_known(self.db(), KnownClass::Any) {
|
||||
SubclassOfType::subclass_of_any()
|
||||
} else {
|
||||
@@ -10288,7 +10294,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
self.infer_expression(&subscript.slice);
|
||||
Type::unknown()
|
||||
}
|
||||
Type::ClassLiteral(literal) if literal.is_known(self.db(), KnownClass::Any) => {
|
||||
Type::ClassSingleton(literal) if literal.is_known(self.db(), KnownClass::Any) => {
|
||||
self.infer_expression(slice);
|
||||
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
|
||||
builder.into_diagnostic("Type `typing.Any` expected no type parameter");
|
||||
@@ -10348,7 +10354,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
self.infer_type_expression(slice);
|
||||
value_ty
|
||||
}
|
||||
Type::ClassLiteral(class) => {
|
||||
Type::ClassSingleton(class) => {
|
||||
match class.generic_context(self.db()) {
|
||||
Some(generic_context) => {
|
||||
let specialized_class = self.infer_explicit_class_specialization(
|
||||
|
||||
@@ -20,7 +20,7 @@ pub(super) use synthesized_protocol::SynthesizedProtocolType;
|
||||
|
||||
impl<'db> Type<'db> {
|
||||
pub(crate) fn instance(db: &'db dyn Db, class: ClassType<'db>) -> Self {
|
||||
let (class_literal, specialization) = class.class_literal(db);
|
||||
let (class_literal, specialization) = class.class_singleton(db);
|
||||
|
||||
match class_literal.known(db) {
|
||||
Some(KnownClass::Any) => Type::Dynamic(DynamicType::Any),
|
||||
@@ -213,7 +213,7 @@ impl<'db> NominalInstanceType<'db> {
|
||||
NominalInstanceInner::ExactTuple(_) => return None,
|
||||
NominalInstanceInner::NonTuple(class) => class,
|
||||
};
|
||||
let (class, Some(specialization)) = class.class_literal(db) else {
|
||||
let (class, Some(specialization)) = class.class_singleton(db) else {
|
||||
return None;
|
||||
};
|
||||
if !class.is_known(db, KnownClass::Slice) {
|
||||
@@ -324,7 +324,7 @@ impl<'db> NominalInstanceType<'db> {
|
||||
NominalInstanceInner::NonTuple(class) => class
|
||||
.known(db)
|
||||
.map(KnownClass::is_singleton)
|
||||
.unwrap_or_else(|| is_single_member_enum(db, class.class_literal(db).0)),
|
||||
.unwrap_or_else(|| is_single_member_enum(db, class.class_singleton(db).0)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,7 +335,7 @@ impl<'db> NominalInstanceType<'db> {
|
||||
.known(db)
|
||||
.and_then(KnownClass::is_single_valued)
|
||||
.or_else(|| Some(self.tuple_spec(db)?.is_single_valued(db)))
|
||||
.unwrap_or_else(|| is_single_member_enum(db, class.class_literal(db).0)),
|
||||
.unwrap_or_else(|| is_single_member_enum(db, class.class_singleton(db).0)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,7 +608,7 @@ impl<'db> Protocol<'db> {
|
||||
fn interface(self, db: &'db dyn Db) -> ProtocolInterface<'db> {
|
||||
match self {
|
||||
Self::FromClass(class) => class
|
||||
.class_literal(db)
|
||||
.class_singleton(db)
|
||||
.0
|
||||
.into_protocol_class(db)
|
||||
.expect("Protocol class literal should be a protocol class")
|
||||
|
||||
@@ -151,7 +151,7 @@ impl<'db> Mro<'db> {
|
||||
)
|
||||
) =>
|
||||
{
|
||||
ClassBase::try_from_type(db, *single_base, class.class_literal(db).0).map_or_else(
|
||||
ClassBase::try_from_type(db, *single_base, class.class_singleton(db).0).map_or_else(
|
||||
|| Err(MroErrorKind::InvalidBases(Box::from([(0, *single_base)]))),
|
||||
|single_base| {
|
||||
if single_base.has_cyclic_mro(db) {
|
||||
@@ -186,7 +186,7 @@ impl<'db> Mro<'db> {
|
||||
&original_bases[i + 1..],
|
||||
);
|
||||
} else {
|
||||
match ClassBase::try_from_type(db, *base, class.class_literal(db).0) {
|
||||
match ClassBase::try_from_type(db, *base, class.class_singleton(db).0) {
|
||||
Some(valid_base) => resolved_bases.push(valid_base),
|
||||
None => invalid_bases.push((i, *base)),
|
||||
}
|
||||
@@ -254,7 +254,7 @@ impl<'db> Mro<'db> {
|
||||
// precise!).
|
||||
for (index, base) in original_bases.iter().enumerate() {
|
||||
let Some(base) =
|
||||
ClassBase::try_from_type(db, *base, class.class_literal(db).0)
|
||||
ClassBase::try_from_type(db, *base, class.class_singleton(db).0)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -183,7 +183,7 @@ impl ClassInfoConstraintFunction {
|
||||
|
||||
match classinfo {
|
||||
Type::TypeAlias(alias) => self.generate_constraint(db, alias.value_type(db)),
|
||||
Type::ClassLiteral(class_literal) => {
|
||||
Type::ClassSingleton(class_literal) => {
|
||||
// At runtime (on Python 3.11+), this will return `True` for classes that actually
|
||||
// do inherit `typing.Any` and `False` otherwise. We could accurately model that?
|
||||
if class_literal.is_known(db, KnownClass::Any) {
|
||||
@@ -573,13 +573,18 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> {
|
||||
}
|
||||
// Treat enums as a union of their members.
|
||||
Type::NominalInstance(instance)
|
||||
if enum_metadata(db, instance.class(db).class_literal(db).0).is_some() =>
|
||||
if enum_metadata(db, instance.class(db).class_singleton(db).0)
|
||||
.is_some() =>
|
||||
{
|
||||
UnionType::from_elements(
|
||||
db,
|
||||
enum_member_literals(db, instance.class(db).class_literal(db).0, None)
|
||||
.expect("Calling `enum_member_literals` on an enum class")
|
||||
.map(|ty| filter_to_cannot_be_equal(db, ty, rhs_ty)),
|
||||
enum_member_literals(
|
||||
db,
|
||||
instance.class(db).class_singleton(db).0,
|
||||
None,
|
||||
)
|
||||
.expect("Calling `enum_member_literals` on an enum class")
|
||||
.map(|ty| filter_to_cannot_be_equal(db, ty, rhs_ty)),
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
@@ -757,7 +762,7 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> {
|
||||
node_index: _,
|
||||
},
|
||||
}) if keywords.is_empty() => {
|
||||
let Type::ClassLiteral(rhs_class) = rhs_ty else {
|
||||
let Type::ClassSingleton(rhs_class) = rhs_ty else {
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -784,7 +789,7 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> {
|
||||
let callable_type = inference.expression_type(&**callable);
|
||||
|
||||
if callable_type
|
||||
.into_class_literal()
|
||||
.into_class_singleton()
|
||||
.is_some_and(|c| c.is_known(self.db, KnownClass::Type))
|
||||
{
|
||||
let place = self.expect_place(&target);
|
||||
@@ -881,7 +886,7 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> {
|
||||
})
|
||||
}
|
||||
// for the expression `bool(E)`, we further narrow the type based on `E`
|
||||
Type::ClassLiteral(class_type)
|
||||
Type::ClassSingleton(class_type)
|
||||
if expr_call.arguments.args.len() == 1
|
||||
&& expr_call.arguments.keywords.is_empty()
|
||||
&& class_type.is_known(self.db, KnownClass::Bool) =>
|
||||
|
||||
@@ -145,7 +145,7 @@ impl Ty {
|
||||
known_module_symbol(db, KnownModule::Uuid, "SafeUUID")
|
||||
.place
|
||||
.expect_type()
|
||||
.expect_class_literal(),
|
||||
.expect_class_singleton(),
|
||||
Name::new(name),
|
||||
)),
|
||||
Ty::SingleMemberEnumLiteral => {
|
||||
@@ -153,7 +153,7 @@ impl Ty {
|
||||
.place
|
||||
.expect_type();
|
||||
debug_assert!(
|
||||
matches!(ty, Type::NominalInstance(instance) if is_single_member_enum(db, instance.class(db).class_literal(db).0))
|
||||
matches!(ty, Type::NominalInstance(instance) if is_single_member_enum(db, instance.class(db).class_singleton(db).0))
|
||||
);
|
||||
ty
|
||||
}
|
||||
@@ -209,7 +209,7 @@ impl Ty {
|
||||
builtins_symbol(db, s)
|
||||
.place
|
||||
.expect_type()
|
||||
.expect_class_literal()
|
||||
.expect_class_singleton()
|
||||
.default_specialization(db),
|
||||
),
|
||||
Ty::SubclassOfAbcClass(s) => SubclassOfType::from(
|
||||
@@ -217,7 +217,7 @@ impl Ty {
|
||||
known_module_symbol(db, KnownModule::Abc, s)
|
||||
.place
|
||||
.expect_type()
|
||||
.expect_class_literal()
|
||||
.expect_class_singleton()
|
||||
.default_specialization(db),
|
||||
),
|
||||
Ty::AlwaysTruthy => Type::AlwaysTruthy,
|
||||
|
||||
@@ -528,7 +528,7 @@ fn cached_protocol_interface<'db>(
|
||||
for parent_protocol in class
|
||||
.iter_mro(db, None)
|
||||
.filter_map(ClassBase::into_class)
|
||||
.filter_map(|class| class.class_literal(db).0.into_protocol_class(db))
|
||||
.filter_map(|class| class.class_singleton(db).0.into_protocol_class(db))
|
||||
{
|
||||
let parent_scope = parent_protocol.body_scope(db);
|
||||
let use_def_map = use_def_map(db, parent_scope);
|
||||
|
||||
@@ -253,7 +253,7 @@ impl SpecialFormType {
|
||||
}
|
||||
|
||||
pub(super) fn to_meta_type(self, db: &dyn Db) -> Type<'_> {
|
||||
self.class().to_class_literal(db)
|
||||
self.class().to_class_singleton(db)
|
||||
}
|
||||
|
||||
/// Return true if this special form is callable at runtime.
|
||||
|
||||
@@ -211,7 +211,7 @@ impl<'db> SubclassOfType<'db> {
|
||||
pub(crate) fn is_typed_dict(self, db: &'db dyn Db) -> bool {
|
||||
self.subclass_of
|
||||
.into_class()
|
||||
.is_some_and(|class| class.class_literal(db).0.is_typed_dict(db))
|
||||
.is_some_and(|class| class.class_singleton(db).0.is_typed_dict(db))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,7 +268,7 @@ impl<'db> SubclassOfInner<'db> {
|
||||
pub(crate) fn try_from_type(db: &'db dyn Db, ty: Type<'db>) -> Option<Self> {
|
||||
match ty {
|
||||
Type::Dynamic(dynamic) => Some(Self::Dynamic(dynamic)),
|
||||
Type::ClassLiteral(literal) => Some(if literal.is_known(db, KnownClass::Any) {
|
||||
Type::ClassSingleton(literal) => Some(if literal.is_known(db, KnownClass::Any) {
|
||||
Self::Dynamic(DynamicType::Any)
|
||||
} else {
|
||||
Self::Class(literal.default_specialization(db))
|
||||
|
||||
@@ -201,7 +201,7 @@ impl<'db> TupleType<'db> {
|
||||
#[salsa::tracked(cycle_fn=to_class_type_cycle_recover, cycle_initial=to_class_type_cycle_initial, heap_size=ruff_memory_usage::heap_size)]
|
||||
pub(crate) fn to_class_type(self, db: &'db dyn Db) -> ClassType<'db> {
|
||||
let tuple_class = KnownClass::Tuple
|
||||
.try_to_class_literal(db)
|
||||
.try_to_class_singleton(db)
|
||||
.expect("Typeshed should always have a `tuple` class in `builtins.pyi`");
|
||||
|
||||
tuple_class.apply_specialization(db, |generic_context| {
|
||||
@@ -285,7 +285,7 @@ fn to_class_type_cycle_recover<'db>(
|
||||
|
||||
fn to_class_type_cycle_initial<'db>(db: &'db dyn Db, self_: TupleType<'db>) -> ClassType<'db> {
|
||||
let tuple_class = KnownClass::Tuple
|
||||
.try_to_class_literal(db)
|
||||
.try_to_class_singleton(db)
|
||||
.expect("Typeshed should always have a `tuple` class in `builtins.pyi`");
|
||||
|
||||
tuple_class.apply_specialization(db, |generic_context| {
|
||||
|
||||
@@ -104,9 +104,9 @@ pub(super) fn union_or_intersection_elements_ordering<'db>(
|
||||
(Type::ModuleLiteral(_), _) => Ordering::Less,
|
||||
(_, Type::ModuleLiteral(_)) => Ordering::Greater,
|
||||
|
||||
(Type::ClassLiteral(left), Type::ClassLiteral(right)) => left.cmp(right),
|
||||
(Type::ClassLiteral(_), _) => Ordering::Less,
|
||||
(_, Type::ClassLiteral(_)) => Ordering::Greater,
|
||||
(Type::ClassSingleton(left), Type::ClassSingleton(right)) => left.cmp(right),
|
||||
(Type::ClassSingleton(_), _) => Ordering::Less,
|
||||
(_, Type::ClassSingleton(_)) => Ordering::Greater,
|
||||
|
||||
(Type::GenericAlias(left), Type::GenericAlias(right)) => left.cmp(right),
|
||||
(Type::GenericAlias(_), _) => Ordering::Less,
|
||||
|
||||
@@ -142,7 +142,7 @@ impl<'db> From<Type<'db>> for TypeKind<'db> {
|
||||
| Type::DataclassTransformer(_)
|
||||
| Type::WrapperDescriptor(_)
|
||||
| Type::ModuleLiteral(_)
|
||||
| Type::ClassLiteral(_)
|
||||
| Type::ClassSingleton(_)
|
||||
| Type::SpecialForm(_)
|
||||
| Type::Dynamic(_) => TypeKind::Atomic,
|
||||
|
||||
|
||||
Reference in New Issue
Block a user