@@ -45,7 +45,7 @@ use crate::types::constraints::{
45
45
use crate :: types:: context:: { LintDiagnosticGuard , LintDiagnosticGuardBuilder } ;
46
46
use crate :: types:: diagnostic:: { INVALID_AWAIT , INVALID_TYPE_FORM , UNSUPPORTED_BOOL_CONVERSION } ;
47
47
pub use crate :: types:: display:: DisplaySettings ;
48
- use crate :: types:: enums:: { enum_metadata, is_single_member_enum} ;
48
+ use crate :: types:: enums:: { enum_member_literals , enum_metadata, is_single_member_enum} ;
49
49
use crate :: types:: function:: {
50
50
DataclassTransformerParams , FunctionDecorators , FunctionSpans , FunctionType , KnownFunction ,
51
51
} ;
@@ -4917,6 +4917,8 @@ impl<'db> Type<'db> {
4917
4917
db : & ' db dyn Db ,
4918
4918
mode : EvaluationMode ,
4919
4919
) -> Result < Cow < ' db , TupleSpec < ' db > > , IterationError < ' db > > {
4920
+ const MAX_TUPLE_LENGTH : usize = 128 ;
4921
+
4920
4922
if mode. is_async ( ) {
4921
4923
let try_call_dunder_anext_on_iterator = |iterator : Type < ' db > | -> Result <
4922
4924
Result < Type < ' db > , AwaitError < ' db > > ,
@@ -4984,14 +4986,24 @@ impl<'db> Type<'db> {
4984
4986
) ) ) ) ;
4985
4987
}
4986
4988
Type :: StringLiteral ( string_literal_ty) => {
4987
- // We could go further and deconstruct to an array of `StringLiteral`
4988
- // with each individual character, instead of just an array of
4989
- // `LiteralString`, but there would be a cost and it's not clear that
4990
- // it's worth it.
4991
- return Ok ( Cow :: Owned ( TupleSpec :: heterogeneous ( std:: iter:: repeat_n (
4992
- Type :: LiteralString ,
4993
- string_literal_ty. python_len ( db) ,
4994
- ) ) ) ) ;
4989
+ let string_literal = string_literal_ty. value ( db) ;
4990
+ if string_literal. len ( ) < MAX_TUPLE_LENGTH {
4991
+ return Ok ( Cow :: Owned ( TupleSpec :: heterogeneous (
4992
+ string_literal
4993
+ . chars ( )
4994
+ . map ( |c| Type :: string_literal ( db, & c. to_string ( ) ) ) ,
4995
+ ) ) ) ;
4996
+ }
4997
+ }
4998
+ Type :: BytesLiteral ( bytes) => {
4999
+ let bytes_literal = bytes. value ( db) ;
5000
+ if bytes_literal. len ( ) < MAX_TUPLE_LENGTH {
5001
+ return Ok ( Cow :: Owned ( TupleSpec :: heterogeneous (
5002
+ bytes_literal
5003
+ . iter ( )
5004
+ . map ( |b| Type :: IntLiteral ( i64:: from ( * b) ) ) ,
5005
+ ) ) ) ;
5006
+ }
4995
5007
}
4996
5008
Type :: Never => {
4997
5009
// The dunder logic below would have us return `tuple[Never, ...]`, which eagerly
@@ -5016,6 +5028,15 @@ impl<'db> Type<'db> {
5016
5028
"should not be able to iterate over type variable {} in inferable position" ,
5017
5029
self . display( db)
5018
5030
) ,
5031
+ Type :: ClassLiteral ( class) => {
5032
+ if let Some ( enum_members) = enum_member_literals ( db, class, None ) {
5033
+ if enum_metadata ( db, class)
5034
+ . is_some_and ( |metadata| metadata. members . len ( ) < MAX_TUPLE_LENGTH )
5035
+ {
5036
+ return Ok ( Cow :: Owned ( TupleSpec :: heterogeneous ( enum_members) ) ) ;
5037
+ }
5038
+ }
5039
+ }
5019
5040
Type :: Dynamic ( _)
5020
5041
| Type :: FunctionLiteral ( _)
5021
5042
| Type :: GenericAlias ( _)
@@ -5026,7 +5047,6 @@ impl<'db> Type<'db> {
5026
5047
| Type :: DataclassTransformer ( _)
5027
5048
| Type :: Callable ( _)
5028
5049
| Type :: ModuleLiteral ( _)
5029
- | Type :: ClassLiteral ( _)
5030
5050
| Type :: SubclassOf ( _)
5031
5051
| Type :: ProtocolInstance ( _)
5032
5052
| Type :: SpecialForm ( _)
@@ -5040,7 +5060,6 @@ impl<'db> Type<'db> {
5040
5060
| Type :: BooleanLiteral ( _)
5041
5061
| Type :: EnumLiteral ( _)
5042
5062
| Type :: LiteralString
5043
- | Type :: BytesLiteral ( _)
5044
5063
| Type :: BoundSuper ( _)
5045
5064
| Type :: TypeIs ( _)
5046
5065
| Type :: TypedDict ( _) => { }
0 commit comments