@@ -575,7 +575,7 @@ impl<'db> ClassType<'db> {
575575 pub ( super ) fn own_class_member ( self , db : & ' db dyn Db , name : & str ) -> PlaceAndQualifiers < ' db > {
576576 let ( class_literal, specialization) = self . class_literal ( db) ;
577577
578- let synthesize_tuple_method = |return_type| {
578+ let synthesize_simple_tuple_method = |return_type| {
579579 let parameters =
580580 Parameters :: new ( [ Parameter :: positional_only ( Some ( Name :: new_static ( "self" ) ) )
581581 . with_annotated_type ( Type :: instance ( db, self ) ) ] ) ;
@@ -587,22 +587,88 @@ impl<'db> ClassType<'db> {
587587 } ;
588588
589589 match name {
590- "__len__" if class_literal. is_known ( db, KnownClass :: Tuple ) => {
590+ "__len__" if class_literal. is_tuple ( db) => {
591591 let return_type = specialization
592592 . and_then ( |spec| spec. tuple ( db) . len ( ) . into_fixed_length ( ) )
593593 . and_then ( |len| i64:: try_from ( len) . ok ( ) )
594594 . map ( Type :: IntLiteral )
595595 . unwrap_or_else ( || KnownClass :: Int . to_instance ( db) ) ;
596596
597- synthesize_tuple_method ( return_type)
597+ synthesize_simple_tuple_method ( return_type)
598598 }
599- "__bool__" if class_literal. is_known ( db, KnownClass :: Tuple ) => {
599+
600+ "__bool__" if class_literal. is_tuple ( db) => {
600601 let return_type = specialization
601602 . map ( |spec| spec. tuple ( db) . truthiness ( ) . into_type ( db) )
602603 . unwrap_or_else ( || KnownClass :: Bool . to_instance ( db) ) ;
603604
604- synthesize_tuple_method ( return_type)
605+ synthesize_simple_tuple_method ( return_type)
605606 }
607+
608+ // ```py
609+ // class tuple:
610+ // @overload
611+ // def __new__(cls: type[tuple[()]], iterable: tuple[()] = ()) -> tuple[()]: ...
612+ // @overload
613+ // def __new__[T](cls: type[tuple[T, ...]], iterable: tuple[T, ...]) -> tuple[T, ...]: ...
614+ // ```
615+ "__new__" if class_literal. is_tuple ( db) => {
616+ let mut iterable_parameter =
617+ Parameter :: positional_only ( Some ( Name :: new_static ( "iterable" ) ) ) ;
618+
619+ match specialization {
620+ Some ( spec) => {
621+ let tuple = spec. tuple ( db) ;
622+ let tuple_len = tuple. len ( ) ;
623+
624+ if tuple_len. minimum ( ) == 0 && tuple_len. maximum ( ) . is_none ( ) {
625+ // If the tuple has no length restrictions,
626+ // any iterable is allowed as long as the iterable has the correct element type.
627+ let mut tuple_elements = tuple. all_elements ( ) ;
628+ iterable_parameter = iterable_parameter. with_annotated_type (
629+ KnownClass :: Iterable
630+ . to_specialized_instance ( db, [ * tuple_elements. next ( ) . unwrap ( ) ] ) ,
631+ ) ;
632+ assert_eq ! (
633+ tuple_elements. next( ) ,
634+ None ,
635+ "Tuple specialization should not have more than one element when it has no length restriction"
636+ ) ;
637+ } else {
638+ // But if the tuple is of a fixed length, or has a minimum length, we require a tuple rather
639+ // than an iterable, as a tuple is the only kind of iterable for which we can
640+ // specify a fixed length, or that the iterable must be at least a certain length.
641+ iterable_parameter =
642+ iterable_parameter. with_annotated_type ( Type :: instance ( db, self ) ) ;
643+ }
644+ }
645+ None => {
646+ // If the tuple isn't specialized at all, we allow any argument as long as it is iterable.
647+ iterable_parameter = iterable_parameter
648+ . with_annotated_type ( KnownClass :: Iterable . to_instance ( db) ) ;
649+ }
650+ }
651+
652+ // We allow the `iterable` parameter to be omitted for:
653+ // - a zero-length tuple
654+ // - an unspecialized tuple
655+ // - a tuple with no minimum length
656+ if specialization. is_none_or ( |spec| spec. tuple ( db) . len ( ) . minimum ( ) == 0 ) {
657+ iterable_parameter = iterable_parameter. with_default_type ( TupleType :: empty ( db) ) ;
658+ }
659+
660+ let parameters = Parameters :: new ( [
661+ Parameter :: positional_only ( Some ( Name :: new_static ( "self" ) ) )
662+ . with_annotated_type ( SubclassOfType :: from ( db, self ) ) ,
663+ iterable_parameter,
664+ ] ) ;
665+
666+ let synthesized_dunder =
667+ CallableType :: function_like ( db, Signature :: new ( parameters, None ) ) ;
668+
669+ Place :: bound ( synthesized_dunder) . into ( )
670+ }
671+
606672 _ => class_literal
607673 . own_class_member ( db, specialization, name)
608674 . map_type ( |ty| ty. apply_optional_specialization ( db, specialization) ) ,
@@ -659,38 +725,41 @@ impl<'db> ClassType<'db> {
659725 )
660726 . place ;
661727
662- let dunder_new_function =
663- if let Place :: Type ( Type :: FunctionLiteral ( dunder_new_function) , _) =
664- dunder_new_function_symbol
665- {
666- // Step 3: If the return type of the `__new__` evaluates to a type that is not a subclass of this class,
667- // then we should ignore the `__init__` and just return the `__new__` method.
668- let returns_non_subclass =
669- dunder_new_function
670- . signature ( db)
671- . overloads
672- . iter ( )
673- . any ( |signature| {
674- signature. return_ty . is_some_and ( |return_ty| {
675- !return_ty. is_assignable_to (
676- db,
677- self_ty
678- . to_instance ( db)
679- . expect ( "ClassType should be instantiable" ) ,
680- )
681- } )
682- } ) ;
728+ let dunder_new_signature = dunder_new_function_symbol
729+ . ignore_possibly_unbound ( )
730+ . and_then ( |ty| match ty {
731+ Type :: FunctionLiteral ( function) => Some ( function. signature ( db) ) ,
732+ Type :: Callable ( callable) => Some ( callable. signatures ( db) ) ,
733+ _ => None ,
734+ } ) ;
683735
684- let dunder_new_bound_method =
685- dunder_new_function. into_bound_method_type ( db, self_ty) ;
736+ let dunder_new_function = if let Some ( dunder_new_signature) = dunder_new_signature {
737+ // Step 3: If the return type of the `__new__` evaluates to a type that is not a subclass of this class,
738+ // then we should ignore the `__init__` and just return the `__new__` method.
739+ let returns_non_subclass = dunder_new_signature. overloads . iter ( ) . any ( |signature| {
740+ signature. return_ty . is_some_and ( |return_ty| {
741+ !return_ty. is_assignable_to (
742+ db,
743+ self_ty
744+ . to_instance ( db)
745+ . expect ( "ClassType should be instantiable" ) ,
746+ )
747+ } )
748+ } ) ;
686749
687- if returns_non_subclass {
688- return dunder_new_bound_method;
689- }
690- Some ( dunder_new_bound_method)
691- } else {
692- None
693- } ;
750+ let dunder_new_bound_method = Type :: Callable ( CallableType :: new (
751+ db,
752+ dunder_new_signature. bind_self ( ) ,
753+ true ,
754+ ) ) ;
755+
756+ if returns_non_subclass {
757+ return dunder_new_bound_method;
758+ }
759+ Some ( dunder_new_bound_method)
760+ } else {
761+ None
762+ } ;
694763
695764 let dunder_init_function_symbol = self_ty
696765 . member_lookup_with_policy (
@@ -864,6 +933,10 @@ impl<'db> ClassLiteral<'db> {
864933 self . known ( db) == Some ( known_class)
865934 }
866935
936+ pub ( crate ) fn is_tuple ( self , db : & ' db dyn Db ) -> bool {
937+ self . is_known ( db, KnownClass :: Tuple )
938+ }
939+
867940 pub ( crate ) fn generic_context ( self , db : & ' db dyn Db ) -> Option < GenericContext < ' db > > {
868941 // Several typeshed definitions examine `sys.version_info`. To break cycles, we hard-code
869942 // the knowledge that this class is not generic.
0 commit comments