-
Notifications
You must be signed in to change notification settings - Fork 1.8k
[ty] Support dataclass-transform field_specifiers
#20888
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b947075
9645d45
004dd5f
826f933
912bd5c
1775f93
7af070e
2feafaa
2642e6e
da86f28
13688d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,7 +32,9 @@ pub(crate) use self::signatures::{CallableSignature, Parameter, Parameters, Sign | |
| pub(crate) use self::subclass_of::{SubclassOfInner, SubclassOfType}; | ||
| use crate::module_name::ModuleName; | ||
| use crate::module_resolver::{KnownModule, resolve_module}; | ||
| use crate::place::{Definedness, Place, PlaceAndQualifiers, TypeOrigin, imported_symbol}; | ||
| use crate::place::{ | ||
| Definedness, Place, PlaceAndQualifiers, TypeOrigin, imported_symbol, known_module_symbol, | ||
| }; | ||
| use crate::semantic_index::definition::{Definition, DefinitionKind}; | ||
| use crate::semantic_index::place::ScopedPlaceId; | ||
| use crate::semantic_index::scope::ScopeId; | ||
|
|
@@ -50,7 +52,8 @@ pub use crate::types::display::DisplaySettings; | |
| use crate::types::display::TupleSpecialization; | ||
| use crate::types::enums::{enum_metadata, is_single_member_enum}; | ||
| use crate::types::function::{ | ||
| DataclassTransformerParams, FunctionSpans, FunctionType, KnownFunction, | ||
| DataclassTransformerFlags, DataclassTransformerParams, FunctionSpans, FunctionType, | ||
| KnownFunction, | ||
| }; | ||
| use crate::types::generics::{ | ||
| GenericContext, InferableTypeVars, PartialSpecialization, Specialization, bind_typevar, | ||
|
|
@@ -618,67 +621,95 @@ impl<'db> PropertyInstanceType<'db> { | |
| } | ||
|
|
||
| bitflags! { | ||
| /// Used for the return type of `dataclass(…)` calls. Keeps track of the arguments | ||
| /// that were passed in. For the precise meaning of the fields, see [1]. | ||
| /// Used to store metadata about a dataclass or dataclass-like class. | ||
| /// For the precise meaning of the fields, see [1]. | ||
| /// | ||
| /// [1]: https://docs.python.org/3/library/dataclasses.html | ||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
| pub struct DataclassParams: u16 { | ||
| const INIT = 0b0000_0000_0001; | ||
| const REPR = 0b0000_0000_0010; | ||
| const EQ = 0b0000_0000_0100; | ||
| const ORDER = 0b0000_0000_1000; | ||
| const UNSAFE_HASH = 0b0000_0001_0000; | ||
| const FROZEN = 0b0000_0010_0000; | ||
| const MATCH_ARGS = 0b0000_0100_0000; | ||
| const KW_ONLY = 0b0000_1000_0000; | ||
| const SLOTS = 0b0001_0000_0000; | ||
| const WEAKREF_SLOT = 0b0010_0000_0000; | ||
| // This is not an actual argument from `dataclass(...)` but a flag signaling that no | ||
| // `field_specifiers` was specified for the `dataclass_transform`, see [1]. | ||
| // [1]: https://typing.python.org/en/latest/spec/dataclasses.html#dataclass-transform-parameters | ||
| const NO_FIELD_SPECIFIERS = 0b0100_0000_0000; | ||
| } | ||
| } | ||
|
|
||
| impl get_size2::GetSize for DataclassParams {} | ||
|
|
||
| impl Default for DataclassParams { | ||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] | ||
| pub struct DataclassFlags: u16 { | ||
| const INIT = 1 << 0; | ||
| const REPR = 1 << 1; | ||
| const EQ = 1 << 2; | ||
| const ORDER = 1 << 3; | ||
| const UNSAFE_HASH = 1 << 4; | ||
| const FROZEN = 1 << 5; | ||
| const MATCH_ARGS = 1 << 6; | ||
| const KW_ONLY = 1 << 7; | ||
| const SLOTS = 1 << 8 ; | ||
| const WEAKREF_SLOT = 1 << 9; | ||
| } | ||
| } | ||
|
|
||
| impl get_size2::GetSize for DataclassFlags {} | ||
|
|
||
| impl Default for DataclassFlags { | ||
| fn default() -> Self { | ||
| Self::INIT | Self::REPR | Self::EQ | Self::MATCH_ARGS | ||
| } | ||
| } | ||
|
|
||
| impl From<DataclassTransformerParams> for DataclassParams { | ||
| fn from(params: DataclassTransformerParams) -> Self { | ||
| impl From<DataclassTransformerFlags> for DataclassFlags { | ||
| fn from(params: DataclassTransformerFlags) -> Self { | ||
| let mut result = Self::default(); | ||
|
|
||
| result.set( | ||
| Self::EQ, | ||
| params.contains(DataclassTransformerParams::EQ_DEFAULT), | ||
| params.contains(DataclassTransformerFlags::EQ_DEFAULT), | ||
| ); | ||
| result.set( | ||
| Self::ORDER, | ||
| params.contains(DataclassTransformerParams::ORDER_DEFAULT), | ||
| params.contains(DataclassTransformerFlags::ORDER_DEFAULT), | ||
| ); | ||
| result.set( | ||
| Self::KW_ONLY, | ||
| params.contains(DataclassTransformerParams::KW_ONLY_DEFAULT), | ||
| params.contains(DataclassTransformerFlags::KW_ONLY_DEFAULT), | ||
| ); | ||
| result.set( | ||
| Self::FROZEN, | ||
| params.contains(DataclassTransformerParams::FROZEN_DEFAULT), | ||
| ); | ||
|
|
||
| result.set( | ||
| Self::NO_FIELD_SPECIFIERS, | ||
| !params.contains(DataclassTransformerParams::FIELD_SPECIFIERS), | ||
| params.contains(DataclassTransformerFlags::FROZEN_DEFAULT), | ||
| ); | ||
|
|
||
| result | ||
| } | ||
| } | ||
|
|
||
| /// Metadata for a dataclass. Stored inside a `Type::DataclassDecorator(…)` | ||
| /// instance that we use as the return type of a `dataclasses.dataclass` and | ||
| /// dataclass-transformer decorator calls. | ||
| #[salsa::interned(debug, heap_size=ruff_memory_usage::heap_size)] | ||
| #[derive(PartialOrd, Ord)] | ||
| pub struct DataclassParams<'db> { | ||
| flags: DataclassFlags, | ||
|
|
||
| #[returns(deref)] | ||
| field_specifiers: Box<[Type<'db>]>, | ||
| } | ||
|
|
||
| impl get_size2::GetSize for DataclassParams<'_> {} | ||
|
|
||
| impl<'db> DataclassParams<'db> { | ||
| fn default_params(db: &'db dyn Db) -> Self { | ||
| Self::from_flags(db, DataclassFlags::default()) | ||
| } | ||
|
|
||
| fn from_flags(db: &'db dyn Db, flags: DataclassFlags) -> Self { | ||
| let dataclasses_field = known_module_symbol(db, KnownModule::Dataclasses, "field") | ||
| .place | ||
| .ignore_possibly_undefined() | ||
| .unwrap_or_else(Type::unknown); | ||
|
|
||
| Self::new(db, flags, vec![dataclasses_field].into_boxed_slice()) | ||
| } | ||
|
Comment on lines
+695
to
+702
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am sort-of morbidly curious about what does happen to our inference if you try to define a dataclass, with |
||
|
|
||
| fn from_transformer_params(db: &'db dyn Db, params: DataclassTransformerParams<'db>) -> Self { | ||
| Self::new( | ||
| db, | ||
| DataclassFlags::from(params.flags(db)), | ||
| params.field_specifiers(db), | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| /// Representation of a type: a set of possible values at runtime. | ||
| /// | ||
| #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, salsa::Update, get_size2::GetSize)] | ||
|
|
@@ -719,9 +750,9 @@ pub enum Type<'db> { | |
| /// A special callable that is returned by a `dataclass(…)` call. It is usually | ||
| /// used as a decorator. Note that this is only used as a return type for actual | ||
| /// `dataclass` calls, not for the argumentless `@dataclass` decorator. | ||
| DataclassDecorator(DataclassParams), | ||
| DataclassDecorator(DataclassParams<'db>), | ||
| /// A special callable that is returned by a `dataclass_transform(…)` call. | ||
| DataclassTransformer(DataclassTransformerParams), | ||
| DataclassTransformer(DataclassTransformerParams<'db>), | ||
| /// The type of an arbitrary callable object with a certain specified signature. | ||
| Callable(CallableType<'db>), | ||
| /// A specific module object | ||
|
|
@@ -5448,7 +5479,7 @@ impl<'db> Type<'db> { | |
| ) -> Result<Bindings<'db>, CallError<'db>> { | ||
| self.bindings(db) | ||
| .match_parameters(db, argument_types) | ||
| .check_types(db, argument_types, &TypeContext::default()) | ||
| .check_types(db, argument_types, &TypeContext::default(), &[]) | ||
| } | ||
|
|
||
| /// Look up a dunder method on the meta-type of `self` and call it. | ||
|
|
@@ -5500,7 +5531,7 @@ impl<'db> Type<'db> { | |
| let bindings = dunder_callable | ||
| .bindings(db) | ||
| .match_parameters(db, argument_types) | ||
| .check_types(db, argument_types, &tcx)?; | ||
| .check_types(db, argument_types, &tcx, &[])?; | ||
| if boundness == Definedness::PossiblyUndefined { | ||
| return Err(CallDunderError::PossiblyUnbound(Box::new(bindings))); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[insert "all your base are belong to us" joke]