mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 13:24:57 +00:00
[ty] Completely ignore typeshed's stub for Any
(#20079)
This commit is contained in:
parent
d0bcf56bd9
commit
a04823cfad
12 changed files with 134 additions and 105 deletions
|
@ -137,6 +137,22 @@ from unittest.mock import MagicMock
|
|||
x: int = MagicMock()
|
||||
```
|
||||
|
||||
## Runtime properties
|
||||
|
||||
`typing.Any` is a class at runtime on Python 3.11+, and `typing_extensions.Any` is always a class.
|
||||
On earlier versions of Python, `typing.Any` was an instance of `typing._SpecialForm`, but this is
|
||||
not currently modeled by ty. We currently infer `Any` has having all attributes a class would have
|
||||
on all versions of Python:
|
||||
|
||||
```py
|
||||
from typing import Any
|
||||
from ty_extensions import TypeOf, static_assert, is_assignable_to
|
||||
|
||||
reveal_type(Any.__base__) # revealed: type | None
|
||||
reveal_type(Any.__bases__) # revealed: tuple[type, ...]
|
||||
static_assert(is_assignable_to(TypeOf[Any], type))
|
||||
```
|
||||
|
||||
## Invalid
|
||||
|
||||
`Any` cannot be parameterized:
|
||||
|
@ -144,7 +160,32 @@ x: int = MagicMock()
|
|||
```py
|
||||
from typing import Any
|
||||
|
||||
# error: [invalid-type-form] "Type `typing.Any` expected no type parameter"
|
||||
# error: [invalid-type-form] "Special form `typing.Any` expected no type parameter"
|
||||
def f(x: Any[int]):
|
||||
reveal_type(x) # revealed: Unknown
|
||||
```
|
||||
|
||||
`Any` cannot be called (this leads to a `TypeError` at runtime):
|
||||
|
||||
```py
|
||||
Any() # error: [call-non-callable] "Object of type `typing.Any` is not callable"
|
||||
```
|
||||
|
||||
`Any` also cannot be used as a metaclass (under the hood, this leads to an implicit call to `Any`):
|
||||
|
||||
```py
|
||||
class F(metaclass=Any): ... # error: [invalid-metaclass] "Metaclass type `typing.Any` is not callable"
|
||||
```
|
||||
|
||||
And `Any` cannot be used in `isinstance()` checks:
|
||||
|
||||
```py
|
||||
# error: [invalid-argument-type] "`typing.Any` cannot be used with `isinstance()`: This call will raise `TypeError` at runtime"
|
||||
isinstance("", Any)
|
||||
```
|
||||
|
||||
But `issubclass()` checks are fine:
|
||||
|
||||
```py
|
||||
issubclass(object, Any) # no error!
|
||||
```
|
||||
|
|
|
@ -221,11 +221,11 @@ static_assert(is_assignable_to(type[Unknown], Meta))
|
|||
static_assert(is_assignable_to(Meta, type[Any]))
|
||||
static_assert(is_assignable_to(Meta, type[Unknown]))
|
||||
|
||||
class AnyMeta(metaclass=Any): ...
|
||||
|
||||
static_assert(is_assignable_to(type[AnyMeta], type))
|
||||
static_assert(is_assignable_to(type[AnyMeta], type[object]))
|
||||
static_assert(is_assignable_to(type[AnyMeta], type[Any]))
|
||||
def _(x: Any):
|
||||
class AnyMeta(metaclass=x): ...
|
||||
static_assert(is_assignable_to(type[AnyMeta], type))
|
||||
static_assert(is_assignable_to(type[AnyMeta], type[object]))
|
||||
static_assert(is_assignable_to(type[AnyMeta], type[Any]))
|
||||
|
||||
from typing import TypeVar, Generic, Any
|
||||
|
||||
|
|
|
@ -5528,7 +5528,6 @@ impl<'db> Type<'db> {
|
|||
// https://typing.python.org/en/latest/spec/special-types.html#special-cases-for-float-and-complex
|
||||
Type::ClassLiteral(class) => {
|
||||
let ty = match class.known(db) {
|
||||
Some(KnownClass::Any) => Type::any(),
|
||||
Some(KnownClass::Complex) => UnionType::from_elements(
|
||||
db,
|
||||
[
|
||||
|
@ -5622,6 +5621,7 @@ impl<'db> Type<'db> {
|
|||
Type::SpecialForm(special_form) => match special_form {
|
||||
SpecialFormType::Never | SpecialFormType::NoReturn => Ok(Type::Never),
|
||||
SpecialFormType::LiteralString => Ok(Type::LiteralString),
|
||||
SpecialFormType::Any => Ok(Type::any()),
|
||||
SpecialFormType::Unknown => Ok(Type::unknown()),
|
||||
SpecialFormType::AlwaysTruthy => Ok(Type::AlwaysTruthy),
|
||||
SpecialFormType::AlwaysFalsy => Ok(Type::AlwaysFalsy),
|
||||
|
|
|
@ -3485,7 +3485,6 @@ pub enum KnownClass {
|
|||
// Typeshed
|
||||
NoneType, // Part of `types` for Python >= 3.10
|
||||
// Typing
|
||||
Any,
|
||||
Awaitable,
|
||||
Generator,
|
||||
Deprecated,
|
||||
|
@ -3568,8 +3567,7 @@ impl KnownClass {
|
|||
|
||||
Self::NoneType => Some(Truthiness::AlwaysFalse),
|
||||
|
||||
Self::Any
|
||||
| Self::BaseException
|
||||
Self::BaseException
|
||||
| Self::Exception
|
||||
| Self::ExceptionGroup
|
||||
| Self::Object
|
||||
|
@ -3689,7 +3687,6 @@ impl KnownClass {
|
|||
// Anything with a *runtime* MRO (N.B. sometimes different from the MRO that typeshed gives!)
|
||||
// with length >2, or anything that is implemented in pure Python, is not a solid base.
|
||||
Self::ABCMeta
|
||||
| Self::Any
|
||||
| Self::Awaitable
|
||||
| Self::Generator
|
||||
| Self::Enum
|
||||
|
@ -3762,7 +3759,6 @@ impl KnownClass {
|
|||
| KnownClass::AsyncGeneratorType
|
||||
| KnownClass::CoroutineType
|
||||
| KnownClass::NoneType
|
||||
| KnownClass::Any
|
||||
| KnownClass::StdlibAlias
|
||||
| KnownClass::SpecialForm
|
||||
| KnownClass::TypeVar
|
||||
|
@ -3839,7 +3835,6 @@ impl KnownClass {
|
|||
| KnownClass::AsyncGeneratorType
|
||||
| KnownClass::CoroutineType
|
||||
| KnownClass::NoneType
|
||||
| KnownClass::Any
|
||||
| KnownClass::StdlibAlias
|
||||
| KnownClass::SpecialForm
|
||||
| KnownClass::TypeVar
|
||||
|
@ -3916,7 +3911,6 @@ impl KnownClass {
|
|||
| KnownClass::AsyncGeneratorType
|
||||
| KnownClass::CoroutineType
|
||||
| KnownClass::NoneType
|
||||
| KnownClass::Any
|
||||
| KnownClass::StdlibAlias
|
||||
| KnownClass::SpecialForm
|
||||
| KnownClass::TypeVar
|
||||
|
@ -3967,8 +3961,7 @@ impl KnownClass {
|
|||
| Self::NamedTupleLike
|
||||
| Self::Generator => true,
|
||||
|
||||
Self::Any
|
||||
| Self::Bool
|
||||
Self::Bool
|
||||
| Self::Object
|
||||
| Self::Bytes
|
||||
| Self::Bytearray
|
||||
|
@ -4037,7 +4030,6 @@ impl KnownClass {
|
|||
|
||||
pub(crate) fn name(self, db: &dyn Db) -> &'static str {
|
||||
match self {
|
||||
Self::Any => "Any",
|
||||
Self::Bool => "bool",
|
||||
Self::Object => "object",
|
||||
Self::Bytes => "bytes",
|
||||
|
@ -4347,8 +4339,7 @@ impl KnownClass {
|
|||
| Self::UnionType
|
||||
| Self::WrapperDescriptorType => KnownModule::Types,
|
||||
Self::NoneType => KnownModule::Typeshed,
|
||||
Self::Any
|
||||
| Self::Awaitable
|
||||
Self::Awaitable
|
||||
| Self::Generator
|
||||
| Self::SpecialForm
|
||||
| Self::TypeVar
|
||||
|
@ -4409,8 +4400,7 @@ impl KnownClass {
|
|||
| Self::UnionType
|
||||
| Self::NotImplementedType => Some(true),
|
||||
|
||||
Self::Any
|
||||
| Self::Bool
|
||||
Self::Bool
|
||||
| Self::Object
|
||||
| Self::Bytes
|
||||
| Self::Bytearray
|
||||
|
@ -4489,8 +4479,7 @@ impl KnownClass {
|
|||
| Self::TypeAliasType
|
||||
| Self::NotImplementedType => true,
|
||||
|
||||
Self::Any
|
||||
| Self::Bool
|
||||
Self::Bool
|
||||
| Self::Object
|
||||
| Self::Bytes
|
||||
| Self::Bytearray
|
||||
|
@ -4565,7 +4554,6 @@ impl KnownClass {
|
|||
// We assert that this match is exhaustive over the right-hand side in the unit test
|
||||
// `known_class_roundtrip_from_str()`
|
||||
let candidate = match class_name {
|
||||
"Any" => Self::Any,
|
||||
"bool" => Self::Bool,
|
||||
"object" => Self::Object,
|
||||
"bytes" => Self::Bytes,
|
||||
|
@ -4655,8 +4643,7 @@ impl KnownClass {
|
|||
/// Return `true` if the module of `self` matches `module`
|
||||
fn check_module(self, db: &dyn Db, module: KnownModule) -> bool {
|
||||
match self {
|
||||
Self::Any
|
||||
| Self::Bool
|
||||
Self::Bool
|
||||
| Self::Object
|
||||
| Self::Bytes
|
||||
| Self::Bytearray
|
||||
|
|
|
@ -77,13 +77,7 @@ impl<'db> ClassBase<'db> {
|
|||
) -> Option<Self> {
|
||||
match ty {
|
||||
Type::Dynamic(dynamic) => Some(Self::Dynamic(dynamic)),
|
||||
Type::ClassLiteral(literal) => {
|
||||
if literal.is_known(db, KnownClass::Any) {
|
||||
Some(Self::Dynamic(DynamicType::Any))
|
||||
} else {
|
||||
Some(Self::Class(literal.default_specialization(db)))
|
||||
}
|
||||
}
|
||||
Type::ClassLiteral(literal) => Some(Self::Class(literal.default_specialization(db))),
|
||||
Type::GenericAlias(generic) => Some(Self::Class(ClassType::Generic(generic))),
|
||||
Type::NominalInstance(instance)
|
||||
if instance.class(db).is_known(db, KnownClass::GenericAlias) =>
|
||||
|
@ -201,6 +195,7 @@ impl<'db> ClassBase<'db> {
|
|||
| SpecialFormType::AlwaysTruthy
|
||||
| SpecialFormType::AlwaysFalsy => None,
|
||||
|
||||
SpecialFormType::Any => Some(Self::Dynamic(DynamicType::Any)),
|
||||
SpecialFormType::Unknown => Some(Self::unknown()),
|
||||
|
||||
SpecialFormType::Protocol => Some(Self::Protocol),
|
||||
|
|
|
@ -76,9 +76,6 @@ impl Display for DisplayType<'_> {
|
|||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
let representation = self.ty.representation(self.db, self.settings);
|
||||
match self.ty {
|
||||
Type::ClassLiteral(literal) if literal.is_known(self.db, KnownClass::Any) => {
|
||||
write!(f, "typing.Any")
|
||||
}
|
||||
Type::IntLiteral(_)
|
||||
| Type::BooleanLiteral(_)
|
||||
| Type::StringLiteral(_)
|
||||
|
|
|
@ -68,7 +68,7 @@ use crate::types::call::{Binding, CallArguments};
|
|||
use crate::types::constraints::Constraints;
|
||||
use crate::types::context::InferContext;
|
||||
use crate::types::diagnostic::{
|
||||
REDUNDANT_CAST, STATIC_ASSERT_ERROR, TYPE_ASSERTION_FAILURE,
|
||||
INVALID_ARGUMENT_TYPE, REDUNDANT_CAST, STATIC_ASSERT_ERROR, TYPE_ASSERTION_FAILURE,
|
||||
report_bad_argument_to_get_protocol_members, report_bad_argument_to_protocol_interface,
|
||||
report_runtime_check_against_non_runtime_checkable_protocol,
|
||||
};
|
||||
|
@ -79,8 +79,8 @@ use crate::types::visitor::any_over_type;
|
|||
use crate::types::{
|
||||
BoundMethodType, BoundTypeVarInstance, CallableType, ClassBase, ClassLiteral, ClassType,
|
||||
DeprecatedInstance, DynamicType, HasRelationToVisitor, IsEquivalentVisitor, KnownClass,
|
||||
NormalizedVisitor, Truthiness, Type, TypeMapping, TypeRelation, UnionBuilder, all_members,
|
||||
walk_type_mapping,
|
||||
NormalizedVisitor, SpecialFormType, Truthiness, Type, TypeMapping, TypeRelation, UnionBuilder,
|
||||
all_members, walk_type_mapping,
|
||||
};
|
||||
use crate::{Db, FxOrderSet, ModuleName, resolve_module};
|
||||
|
||||
|
@ -1454,25 +1454,48 @@ impl KnownFunction {
|
|||
}
|
||||
|
||||
KnownFunction::IsInstance | KnownFunction::IsSubclass => {
|
||||
let [Some(first_arg), Some(Type::ClassLiteral(class))] = parameter_types else {
|
||||
let [Some(first_arg), Some(second_argument)] = parameter_types else {
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(protocol_class) = class.into_protocol_class(db) {
|
||||
if !protocol_class.is_runtime_checkable(db) {
|
||||
report_runtime_check_against_non_runtime_checkable_protocol(
|
||||
context,
|
||||
call_expression,
|
||||
protocol_class,
|
||||
self,
|
||||
);
|
||||
}
|
||||
}
|
||||
match second_argument {
|
||||
Type::ClassLiteral(class) => {
|
||||
if let Some(protocol_class) = class.into_protocol_class(db) {
|
||||
if !protocol_class.is_runtime_checkable(db) {
|
||||
report_runtime_check_against_non_runtime_checkable_protocol(
|
||||
context,
|
||||
call_expression,
|
||||
protocol_class,
|
||||
self,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if self == KnownFunction::IsInstance {
|
||||
overload.set_return_type(
|
||||
is_instance_truthiness(db, *first_arg, *class).into_type(db),
|
||||
);
|
||||
if self == KnownFunction::IsInstance {
|
||||
overload.set_return_type(
|
||||
is_instance_truthiness(db, *first_arg, *class).into_type(db),
|
||||
);
|
||||
}
|
||||
}
|
||||
// The special-casing here is necessary because we recognise the symbol `typing.Any` as an
|
||||
// instance of `type` at runtime. Even once we understand typeshed's annotation for
|
||||
// `isinstance()`, we'd continue to accept calls such as `isinstance(x, typing.Any)` without
|
||||
// emitting a diagnostic if we didn't have this branch.
|
||||
Type::SpecialForm(SpecialFormType::Any)
|
||||
if self == KnownFunction::IsInstance =>
|
||||
{
|
||||
let Some(builder) =
|
||||
context.report_lint(&INVALID_ARGUMENT_TYPE, call_expression)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let mut diagnostic = builder.into_diagnostic(format_args!(
|
||||
"`typing.Any` cannot be used with `isinstance()`"
|
||||
));
|
||||
diagnostic
|
||||
.set_primary_message("This call will raise `TypeError` at runtime");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3080,15 +3080,19 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
|
||||
let maybe_known_class = KnownClass::try_from_file_and_name(self.db(), self.file(), name);
|
||||
|
||||
let ty = if maybe_known_class.is_none()
|
||||
&& &name.id == "NamedTuple"
|
||||
&& matches!(
|
||||
let in_typing_module = || {
|
||||
matches!(
|
||||
file_to_module(self.db(), self.file()).and_then(|module| module.known(self.db())),
|
||||
Some(KnownModule::Typing | KnownModule::TypingExtensions)
|
||||
) {
|
||||
Type::SpecialForm(SpecialFormType::NamedTuple)
|
||||
} else {
|
||||
Type::from(ClassLiteral::new(
|
||||
)
|
||||
};
|
||||
|
||||
let ty = match (maybe_known_class, &*name.id) {
|
||||
(None, "NamedTuple") if in_typing_module() => {
|
||||
Type::SpecialForm(SpecialFormType::NamedTuple)
|
||||
}
|
||||
(None, "Any") if in_typing_module() => Type::SpecialForm(SpecialFormType::Any),
|
||||
_ => Type::from(ClassLiteral::new(
|
||||
self.db(),
|
||||
name.id.clone(),
|
||||
body_scope,
|
||||
|
@ -3096,7 +3100,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
deprecated,
|
||||
dataclass_params,
|
||||
dataclass_transformer_params,
|
||||
))
|
||||
)),
|
||||
};
|
||||
|
||||
self.add_declaration_with_binding(
|
||||
|
@ -10242,9 +10246,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
let name_ty = self.infer_expression(slice);
|
||||
match name_ty {
|
||||
Type::ClassLiteral(class_literal) => {
|
||||
if class_literal.is_known(self.db(), KnownClass::Any) {
|
||||
SubclassOfType::subclass_of_any()
|
||||
} else if class_literal.is_protocol(self.db()) {
|
||||
if class_literal.is_protocol(self.db()) {
|
||||
SubclassOfType::from(
|
||||
self.db(),
|
||||
todo_type!("type[T] for protocols").expect_dynamic(),
|
||||
|
@ -10256,6 +10258,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
)
|
||||
}
|
||||
}
|
||||
Type::SpecialForm(SpecialFormType::Any) => SubclassOfType::subclass_of_any(),
|
||||
Type::SpecialForm(SpecialFormType::Unknown) => {
|
||||
SubclassOfType::subclass_of_unknown()
|
||||
}
|
||||
|
@ -10339,13 +10342,6 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.infer_expression(&subscript.slice);
|
||||
Type::unknown()
|
||||
}
|
||||
Type::ClassLiteral(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");
|
||||
}
|
||||
Type::unknown()
|
||||
}
|
||||
Type::SpecialForm(special_form) => {
|
||||
self.infer_parameterized_special_form_type_expression(subscript, special_form)
|
||||
}
|
||||
|
@ -10919,6 +10915,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
| SpecialFormType::TypeAlias
|
||||
| SpecialFormType::TypedDict
|
||||
| SpecialFormType::Unknown
|
||||
| SpecialFormType::Any
|
||||
| SpecialFormType::NamedTuple => {
|
||||
self.infer_type_expression(arguments_slice);
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ use crate::types::enums::is_single_member_enum;
|
|||
use crate::types::protocol_class::walk_protocol_interface;
|
||||
use crate::types::tuple::{TupleSpec, TupleType};
|
||||
use crate::types::{
|
||||
ApplyTypeMappingVisitor, ClassBase, DynamicType, HasRelationToVisitor, IsDisjointVisitor,
|
||||
ApplyTypeMappingVisitor, ClassBase, HasRelationToVisitor, IsDisjointVisitor,
|
||||
IsEquivalentVisitor, NormalizedVisitor, TypeMapping, TypeRelation, VarianceInferable,
|
||||
};
|
||||
use crate::{Db, FxOrderSet};
|
||||
|
@ -23,20 +23,20 @@ impl<'db> Type<'db> {
|
|||
pub(crate) fn instance(db: &'db dyn Db, class: ClassType<'db>) -> Self {
|
||||
let (class_literal, specialization) = class.class_literal(db);
|
||||
|
||||
match class_literal.known(db) {
|
||||
Some(KnownClass::Any) => Type::Dynamic(DynamicType::Any),
|
||||
Some(KnownClass::Tuple) => Type::tuple(TupleType::new(
|
||||
if class_literal.is_known(db, KnownClass::Tuple) {
|
||||
Type::tuple(TupleType::new(
|
||||
db,
|
||||
specialization
|
||||
.and_then(|spec| Some(Cow::Borrowed(spec.tuple(db)?)))
|
||||
.unwrap_or_else(|| Cow::Owned(TupleSpec::homogeneous(Type::unknown())))
|
||||
.as_ref(),
|
||||
)),
|
||||
_ if class_literal.is_protocol(db) => {
|
||||
Self::ProtocolInstance(ProtocolInstanceType::from_class(class))
|
||||
}
|
||||
_ if class_literal.is_typed_dict(db) => Type::typed_dict(class),
|
||||
_ => Type::non_tuple_instance(class),
|
||||
))
|
||||
} else if class_literal.is_protocol(db) {
|
||||
Self::ProtocolInstance(ProtocolInstanceType::from_class(class))
|
||||
} else if class_literal.is_typed_dict(db) {
|
||||
Type::typed_dict(class)
|
||||
} else {
|
||||
Type::non_tuple_instance(class)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -183,15 +183,7 @@ impl ClassInfoConstraintFunction {
|
|||
|
||||
match classinfo {
|
||||
Type::TypeAlias(alias) => self.generate_constraint(db, alias.value_type(db)),
|
||||
Type::ClassLiteral(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) {
|
||||
None
|
||||
} else {
|
||||
Some(constraint_fn(class_literal))
|
||||
}
|
||||
}
|
||||
Type::ClassLiteral(class_literal) => Some(constraint_fn(class_literal)),
|
||||
Type::SubclassOf(subclass_of_ty) => match subclass_of_ty.subclass_of() {
|
||||
SubclassOfInner::Class(ClassType::NonGeneric(class)) => Some(constraint_fn(class)),
|
||||
// It's not valid to use a generic alias as the second argument to `isinstance()` or `issubclass()`,
|
||||
|
|
|
@ -27,6 +27,7 @@ use std::str::FromStr;
|
|||
get_size2::GetSize,
|
||||
)]
|
||||
pub enum SpecialFormType {
|
||||
Any,
|
||||
/// The symbol `typing.Annotated` (which can also be found as `typing_extensions.Annotated`)
|
||||
Annotated,
|
||||
/// The symbol `typing.Literal` (which can also be found as `typing_extensions.Literal`)
|
||||
|
@ -162,7 +163,7 @@ impl SpecialFormType {
|
|||
| Self::Protocol // actually `_ProtocolMeta` at runtime but this is what typeshed says
|
||||
| Self::ReadOnly => KnownClass::SpecialForm,
|
||||
|
||||
Self::Generic => KnownClass::Type,
|
||||
Self::Generic | Self::Any => KnownClass::Type,
|
||||
|
||||
Self::List
|
||||
| Self::Dict
|
||||
|
@ -245,6 +246,7 @@ impl SpecialFormType {
|
|||
| Self::TypingSelf
|
||||
| Self::Protocol
|
||||
| Self::NamedTuple
|
||||
| Self::Any
|
||||
| Self::ReadOnly => {
|
||||
matches!(module, KnownModule::Typing | KnownModule::TypingExtensions)
|
||||
}
|
||||
|
@ -317,6 +319,7 @@ impl SpecialFormType {
|
|||
| Self::TypeIs
|
||||
| Self::ReadOnly
|
||||
| Self::Protocol
|
||||
| Self::Any
|
||||
| Self::Generic => false,
|
||||
}
|
||||
}
|
||||
|
@ -324,6 +327,7 @@ impl SpecialFormType {
|
|||
/// Return the repr of the symbol at runtime
|
||||
pub(super) const fn repr(self) -> &'static str {
|
||||
match self {
|
||||
SpecialFormType::Any => "typing.Any",
|
||||
SpecialFormType::Annotated => "typing.Annotated",
|
||||
SpecialFormType::Literal => "typing.Literal",
|
||||
SpecialFormType::LiteralString => "typing.LiteralString",
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::types::variance::VarianceInferable;
|
|||
use crate::types::{
|
||||
ApplyTypeMappingVisitor, BindingContext, BoundTypeVarInstance, ClassType, DynamicType,
|
||||
HasRelationToVisitor, IsDisjointVisitor, KnownClass, MemberLookupPolicy, NormalizedVisitor,
|
||||
Type, TypeMapping, TypeRelation, TypeVarInstance,
|
||||
SpecialFormType, Type, TypeMapping, TypeRelation, TypeVarInstance,
|
||||
};
|
||||
use crate::{Db, FxOrderSet};
|
||||
|
||||
|
@ -47,14 +47,10 @@ impl<'db> SubclassOfType<'db> {
|
|||
SubclassOfInner::Class(class) => {
|
||||
if class.is_final(db) {
|
||||
Type::from(class)
|
||||
} else if class.is_object(db) {
|
||||
KnownClass::Type.to_instance(db)
|
||||
} else {
|
||||
match class.known(db) {
|
||||
Some(KnownClass::Object) => KnownClass::Type.to_instance(db),
|
||||
Some(KnownClass::Any) => Type::SubclassOf(Self {
|
||||
subclass_of: SubclassOfInner::Dynamic(DynamicType::Any),
|
||||
}),
|
||||
_ => Type::SubclassOf(Self { subclass_of }),
|
||||
}
|
||||
Type::SubclassOf(Self { subclass_of })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -288,12 +284,9 @@ 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) {
|
||||
Self::Dynamic(DynamicType::Any)
|
||||
} else {
|
||||
Self::Class(literal.default_specialization(db))
|
||||
}),
|
||||
Type::ClassLiteral(literal) => Some(Self::Class(literal.default_specialization(db))),
|
||||
Type::GenericAlias(generic) => Some(Self::Class(ClassType::Generic(generic))),
|
||||
Type::SpecialForm(SpecialFormType::Any) => Some(Self::Dynamic(DynamicType::Any)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue