@@ -20,8 +20,8 @@ use crate::types::generics::{Specialization, SpecializationBuilder, Specializati
2020use crate :: types:: signatures:: { Parameter , ParameterForm } ;
2121use crate :: types:: {
2222 todo_type, BoundMethodType , DataclassParams , DataclassTransformerParams , FunctionDecorators ,
23- KnownClass , KnownFunction , KnownInstanceType , MethodWrapperKind , PropertyInstanceType ,
24- TupleType , UnionType , WrapperDescriptorKind ,
23+ FunctionType , KnownClass , KnownFunction , KnownInstanceType , MethodWrapperKind ,
24+ PropertyInstanceType , TupleType , UnionType , WrapperDescriptorKind ,
2525} ;
2626use ruff_db:: diagnostic:: { Annotation , Severity , SubDiagnostic } ;
2727use ruff_python_ast as ast;
@@ -770,29 +770,50 @@ impl<'db> Bindings<'db> {
770770 }
771771
772772 _ => {
773- if let Some ( params) = function_type. dataclass_transformer_params ( db) {
774- // This is a call to a custom function that was decorated with `@dataclass_transformer`.
775- // If this function was called with a keyword argument like `order=False`, we extract
776- // the argument type and overwrite the corresponding flag in `dataclass_params` after
777- // constructing them from the `dataclass_transformer`-parameter defaults.
778-
779- let mut dataclass_params = DataclassParams :: from ( params) ;
773+ let mut handle_dataclass_transformer_params =
774+ |function_type : & FunctionType | {
775+ if let Some ( params) =
776+ function_type. dataclass_transformer_params ( db)
777+ {
778+ // This is a call to a custom function that was decorated with `@dataclass_transformer`.
779+ // If this function was called with a keyword argument like `order=False`, we extract
780+ // the argument type and overwrite the corresponding flag in `dataclass_params` after
781+ // constructing them from the `dataclass_transformer`-parameter defaults.
782+
783+ let mut dataclass_params = DataclassParams :: from ( params) ;
784+
785+ if let Some ( Some ( Type :: BooleanLiteral ( order) ) ) =
786+ callable_signature. iter ( ) . nth ( overload_index) . and_then (
787+ |signature| {
788+ let ( idx, _) = signature
789+ . parameters ( )
790+ . keyword_by_name ( "order" ) ?;
791+ overload. parameter_types ( ) . get ( idx)
792+ } ,
793+ )
794+ {
795+ dataclass_params. set ( DataclassParams :: ORDER , * order) ;
796+ }
780797
781- if let Some ( Some ( Type :: BooleanLiteral ( order) ) ) = callable_signature
798+ overload. set_return_type ( Type :: DataclassDecorator (
799+ dataclass_params,
800+ ) ) ;
801+ }
802+ } ;
803+
804+ // Ideally, either the implementation, or exactly one of the overloads
805+ // of the function can have the dataclass_transform decorator applied.
806+ // However, we do not yet enforce this, and in the case of multiple
807+ // applications of the decorator, we will only consider the last one
808+ // for the return value, since the prior ones will be over-written.
809+ if let Some ( overloaded) = function_type. to_overloaded ( db) {
810+ overloaded
811+ . overloads
782812 . iter ( )
783- . nth ( overload_index)
784- . and_then ( |signature| {
785- let ( idx, _) =
786- signature. parameters ( ) . keyword_by_name ( "order" ) ?;
787- overload. parameter_types ( ) . get ( idx)
788- } )
789- {
790- dataclass_params. set ( DataclassParams :: ORDER , * order) ;
791- }
813+ . for_each ( & mut handle_dataclass_transformer_params) ;
814+ } ;
792815
793- overload
794- . set_return_type ( Type :: DataclassDecorator ( dataclass_params) ) ;
795- }
816+ handle_dataclass_transformer_params ( & function_type) ;
796817 }
797818 } ,
798819
0 commit comments