Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/red_knot_python_semantic/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2950,6 +2950,7 @@ impl<'db> Type<'db> {
// https://typing.readthedocs.io/en/latest/spec/special-types.html#special-cases-for-float-and-complex
Type::ClassLiteral(ClassLiteralType { class }) => {
let ty = match class.known(db) {
Some(KnownClass::Any) => Type::any(),
Some(KnownClass::Complex) => UnionType::from_elements(
db,
[
Expand Down
18 changes: 13 additions & 5 deletions crates/red_knot_python_semantic/src/types/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,7 @@ pub enum KnownClass {
// Typeshed
NoneType, // Part of `types` for Python >= 3.10
// Typing
Any,
StdlibAlias,
SpecialForm,
TypeVar,
Expand Down Expand Up @@ -903,7 +904,8 @@ impl<'db> KnownClass {

Self::NoneType => Truthiness::AlwaysFalse,

Self::BaseException
Self::Any
| Self::BaseException
| Self::Object
| Self::OrderedDict
| Self::BaseExceptionGroup
Expand Down Expand Up @@ -944,6 +946,7 @@ impl<'db> KnownClass {

pub(crate) fn name(self, db: &'db dyn Db) -> &'static str {
match self {
Self::Any => "Any",
Self::Bool => "bool",
Self::Object => "object",
Self::Bytes => "bytes",
Expand Down Expand Up @@ -1150,7 +1153,8 @@ impl<'db> KnownClass {
| Self::MethodWrapperType
| Self::WrapperDescriptorType => KnownModule::Types,
Self::NoneType => KnownModule::Typeshed,
Self::SpecialForm
Self::Any
| Self::SpecialForm
| Self::TypeVar
| Self::StdlibAlias
| Self::SupportsIndex
Expand Down Expand Up @@ -1201,7 +1205,8 @@ impl<'db> KnownClass {
| Self::TypeAliasType
| Self::NotImplementedType => true,

Self::Bool
Self::Any
| Self::Bool
| Self::Object
| Self::Bytes
| Self::Type
Expand Down Expand Up @@ -1258,7 +1263,8 @@ impl<'db> KnownClass {
| Self::TypeAliasType
| Self::NotImplementedType => true,

Self::Bool
Self::Any
| Self::Bool
| Self::Object
| Self::Bytes
| Self::Tuple
Expand Down Expand Up @@ -1311,6 +1317,7 @@ impl<'db> 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,
Expand Down Expand Up @@ -1377,7 +1384,8 @@ impl<'db> KnownClass {
/// Return `true` if the module of `self` matches `module`
fn check_module(self, db: &'db dyn Db, module: KnownModule) -> bool {
match self {
Self::Bool
Self::Any
| Self::Bool
| Self::Object
| Self::Bytes
| Self::Type
Expand Down
6 changes: 5 additions & 1 deletion crates/red_knot_python_semantic/src/types/class_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ impl<'db> ClassBase<'db> {
pub(super) 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(Self::Class(literal.class())),
Type::ClassLiteral(literal) => Some(if literal.class().is_known(db, KnownClass::Any) {
Self::Dynamic(DynamicType::Any)
} else {
Self::Class(literal.class())
}),
Type::Union(_) => None, // TODO -- forces consideration of multiple possible MROs?
Type::Intersection(_) => None, // TODO -- probably incorrect?
Type::Instance(_) => None, // TODO -- handle `__mro_entries__`?
Expand Down
23 changes: 12 additions & 11 deletions crates/red_knot_python_semantic/src/types/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,19 @@ pub struct DisplayType<'db> {
impl Display for DisplayType<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let representation = self.ty.representation(self.db);
if matches!(
self.ty,
match self.ty {
Type::ClassLiteral(literal) if literal.class().is_known(self.db, KnownClass::Any) => {
write!(f, "typing.Any")
}
Type::IntLiteral(_)
| Type::BooleanLiteral(_)
| Type::StringLiteral(_)
| Type::BytesLiteral(_)
| Type::ClassLiteral(_)
| Type::FunctionLiteral(_)
) {
write!(f, "Literal[{representation}]")
} else {
representation.fmt(f)
| Type::BooleanLiteral(_)
| Type::StringLiteral(_)
| Type::BytesLiteral(_)
| Type::ClassLiteral(_)
| Type::FunctionLiteral(_) => {
write!(f, "Literal[{representation}]")
}
_ => representation.fmt(f),
}
}
}
Expand Down
17 changes: 16 additions & 1 deletion crates/red_knot_python_semantic/src/types/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6509,7 +6509,14 @@ impl<'db> TypeInferenceBuilder<'db> {
let name_ty = self.infer_expression(slice);
match name_ty {
Type::ClassLiteral(class_literal_ty) => {
SubclassOfType::from(self.db(), class_literal_ty.class())
if class_literal_ty
.class()
.is_known(self.db(), KnownClass::Any)
{
SubclassOfType::subclass_of_any()
} else {
SubclassOfType::from(self.db(), class_literal_ty.class())
}
}
Type::KnownInstance(KnownInstanceType::Any) => {
SubclassOfType::subclass_of_any()
Expand Down Expand Up @@ -6589,6 +6596,14 @@ impl<'db> TypeInferenceBuilder<'db> {
} = subscript;

match value_ty {
Type::ClassLiteral(literal) if literal.class().is_known(self.db(), KnownClass::Any) => {
self.context.report_lint(
&INVALID_TYPE_FORM,
subscript,
format_args!("Type `typing.Any` expected no type parameter",),
);
Type::unknown()
}
Type::KnownInstance(known_instance) => {
self.infer_parameterized_known_instance_type_expression(subscript, known_instance)
}
Expand Down
10 changes: 9 additions & 1 deletion crates/red_knot_python_semantic/src/types/narrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,15 @@ impl KnownConstraintFunction {
}
Some(builder.build())
}
Type::ClassLiteral(class_literal) => Some(constraint_fn(class_literal.class())),
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.class().is_known(db, KnownClass::Any) {
None
} else {
Some(constraint_fn(class_literal.class()))
}
}
Type::SubclassOf(subclass_of_ty) => {
subclass_of_ty.subclass_of().into_class().map(constraint_fn)
}
Expand Down
2 changes: 1 addition & 1 deletion crates/red_knot_vendored/vendor/typeshed/stdlib/typing.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ if sys.version_info >= (3, 12):
if sys.version_info >= (3, 13):
__all__ += ["get_protocol_members", "is_protocol", "NoDefault", "TypeIs", "ReadOnly"]

Any = object()
class Any: ...

class _Final: ...

Expand Down