Do not treat TypedDict's as descriptors

This commit is contained in:
David Peter 2025-05-26 15:43:33 +02:00
parent cdafb3d81c
commit 1c5029ad91
6 changed files with 37 additions and 8 deletions

View file

@ -5659,6 +5659,7 @@ pub enum DynamicType {
/// A special Todo-variant for PEP-695 `ParamSpec` types. A temporary variant to detect and special-
/// case the handling of these types in `Callable` annotations.
TodoPEP695ParamSpec,
TodoTypedDict,
}
impl DynamicType {
@ -5683,6 +5684,13 @@ impl std::fmt::Display for DynamicType {
f.write_str("@Todo")
}
}
DynamicType::TodoTypedDict => {
if cfg!(debug_assertions) {
f.write_str("@Todo(TypedDict)")
} else {
f.write_str("@Todo")
}
}
}
}
}

View file

@ -20,9 +20,9 @@ use crate::types::diagnostic::{
use crate::types::generics::{Specialization, SpecializationBuilder, SpecializationError};
use crate::types::signatures::{Parameter, ParameterForm};
use crate::types::{
BoundMethodType, DataclassParams, DataclassTransformerParams, FunctionDecorators, FunctionType,
KnownClass, KnownFunction, KnownInstanceType, MethodWrapperKind, PropertyInstanceType,
TupleType, TypeMapping, UnionType, WrapperDescriptorKind, todo_type,
BoundMethodType, DataclassParams, DataclassTransformerParams, DynamicType, FunctionDecorators,
FunctionType, KnownClass, KnownFunction, KnownInstanceType, MethodWrapperKind,
PropertyInstanceType, TupleType, TypeMapping, UnionType, WrapperDescriptorKind,
};
use ruff_db::diagnostic::{Annotation, Diagnostic, Severity, SubDiagnostic};
use ruff_python_ast as ast;
@ -916,7 +916,7 @@ impl<'db> Bindings<'db> {
},
Type::KnownInstance(KnownInstanceType::TypedDict) => {
overload.set_return_type(todo_type!("TypedDict"));
overload.set_return_type(Type::Dynamic(DynamicType::TodoTypedDict));
}
// Not a special case

View file

@ -1070,6 +1070,10 @@ impl<'db> ClassLiteral<'db> {
ClassBase::Generic | ClassBase::Protocol => {
// Skip over these very special class bases that aren't really classes.
}
ClassBase::Dynamic(DynamicType::TodoTypedDict) if name == "__get__" => {
return Symbol::Unbound.into();
}
ClassBase::Dynamic(_) => {
// Note: calling `Type::from(superclass).member()` would be incorrect here.
// What we'd really want is a `Type::Any.own_class_member()` method,

View file

@ -44,7 +44,11 @@ impl<'db> ClassBase<'db> {
ClassBase::Class(class) => class.name(db),
ClassBase::Dynamic(DynamicType::Any) => "Any",
ClassBase::Dynamic(DynamicType::Unknown) => "Unknown",
ClassBase::Dynamic(DynamicType::Todo(_) | DynamicType::TodoPEP695ParamSpec) => "@Todo",
ClassBase::Dynamic(
DynamicType::Todo(_)
| DynamicType::TodoPEP695ParamSpec
| DynamicType::TodoTypedDict,
) => "@Todo",
ClassBase::Protocol => "Protocol",
ClassBase::Generic => "Generic",
}
@ -209,7 +213,9 @@ impl<'db> ClassBase<'db> {
KnownInstanceType::OrderedDict => {
Self::try_from_type(db, KnownClass::OrderedDict.to_class_literal(db))
}
KnownInstanceType::TypedDict => Self::try_from_type(db, todo_type!("TypedDict")),
KnownInstanceType::TypedDict => {
Self::try_from_type(db, Type::Dynamic(DynamicType::TodoTypedDict))
}
KnownInstanceType::Callable => {
Self::try_from_type(db, todo_type!("Support for Callable as a base class"))
}

View file

@ -6075,13 +6075,21 @@ impl<'db> TypeInferenceBuilder<'db> {
(unknown @ Type::Dynamic(DynamicType::Unknown), _, _)
| (_, unknown @ Type::Dynamic(DynamicType::Unknown), _) => Some(unknown),
(
todo @ Type::Dynamic(DynamicType::Todo(_) | DynamicType::TodoPEP695ParamSpec),
todo @ Type::Dynamic(
DynamicType::Todo(_)
| DynamicType::TodoPEP695ParamSpec
| DynamicType::TodoTypedDict,
),
_,
_,
)
| (
_,
todo @ Type::Dynamic(DynamicType::Todo(_) | DynamicType::TodoPEP695ParamSpec),
todo @ Type::Dynamic(
DynamicType::Todo(_)
| DynamicType::TodoPEP695ParamSpec
| DynamicType::TodoTypedDict,
),
_,
) => Some(todo),
(Type::Never, _, _) | (_, Type::Never, _) => Some(Type::Never),

View file

@ -382,5 +382,8 @@ fn dynamic_elements_ordering(left: DynamicType, right: DynamicType) -> Ordering
(DynamicType::TodoPEP695ParamSpec, _) => Ordering::Less,
(_, DynamicType::TodoPEP695ParamSpec) => Ordering::Greater,
(DynamicType::TodoTypedDict, _) => Ordering::Less,
(_, DynamicType::TodoTypedDict) => Ordering::Greater,
}
}