@@ -2,6 +2,7 @@ use infer::nearest_enclosing_class;
22use itertools:: { Either , Itertools } ;
33use ruff_db:: parsed:: parsed_module;
44
5+ use std:: borrow:: Cow ;
56use std:: slice:: Iter ;
67
78use bitflags:: bitflags;
@@ -4614,9 +4615,9 @@ impl<'db> Type<'db> {
46144615 ///
46154616 /// This method should only be used outside of type checking because it omits any errors.
46164617 /// For type checking, use [`try_iterate`](Self::try_iterate) instead.
4617- fn iterate ( self , db : & ' db dyn Db ) -> TupleSpec < ' db > {
4618+ fn iterate ( self , db : & ' db dyn Db ) -> Cow < ' db , TupleSpec < ' db > > {
46184619 self . try_iterate ( db)
4619- . unwrap_or_else ( |err| TupleSpec :: homogeneous ( err. fallback_element_type ( db) ) )
4620+ . unwrap_or_else ( |err| Cow :: Owned ( TupleSpec :: homogeneous ( err. fallback_element_type ( db) ) ) )
46204621 }
46214622
46224623 /// Given the type of an object that is iterated over in some way,
@@ -4628,24 +4629,27 @@ impl<'db> Type<'db> {
46284629 /// ```python
46294630 /// y(*x)
46304631 /// ```
4631- fn try_iterate ( self , db : & ' db dyn Db ) -> Result < TupleSpec < ' db > , IterationError < ' db > > {
4632+ fn try_iterate ( self , db : & ' db dyn Db ) -> Result < Cow < ' db , TupleSpec < ' db > > , IterationError < ' db > > {
46324633 match self {
4633- // XXX: Cow?
4634- Type :: Tuple ( tuple_type) => return Ok ( tuple_type. tuple ( db) . clone ( ) ) ,
4634+ Type :: Tuple ( tuple_type) => return Ok ( Cow :: Borrowed ( tuple_type. tuple ( db) ) ) ,
46354635 Type :: GenericAlias ( alias) if alias. origin ( db) . is_known ( db, KnownClass :: Tuple ) => {
4636- return Ok ( TupleSpec :: homogeneous ( todo_type ! ( "*tuple[] annotations" ) ) ) ;
4636+ return Ok ( Cow :: Owned ( TupleSpec :: homogeneous ( todo_type ! (
4637+ "*tuple[] annotations"
4638+ ) ) ) ) ;
46374639 }
46384640 Type :: StringLiteral ( string_literal_ty) => {
46394641 // We could go further and deconstruct to an array of `StringLiteral`
46404642 // with each individual character, instead of just an array of
46414643 // `LiteralString`, but there would be a cost and it's not clear that
46424644 // it's worth it.
4643- return Ok ( TupleSpec :: from_elements ( std:: iter:: repeat_n (
4645+ return Ok ( Cow :: Owned ( TupleSpec :: from_elements ( std:: iter:: repeat_n (
46444646 Type :: LiteralString ,
46454647 string_literal_ty. python_len ( db) ,
4646- ) ) ) ;
4648+ ) ) ) ) ;
4649+ }
4650+ Type :: LiteralString => {
4651+ return Ok ( Cow :: Owned ( TupleSpec :: homogeneous ( Type :: LiteralString ) ) ) ;
46474652 }
4648- Type :: LiteralString => return Ok ( TupleSpec :: homogeneous ( Type :: LiteralString ) ) ,
46494653 _ => { }
46504654 }
46514655
@@ -4673,7 +4677,7 @@ impl<'db> Type<'db> {
46734677 // `__iter__` is definitely bound and calling it succeeds.
46744678 // See what calling `__next__` on the object returned by `__iter__` gives us...
46754679 try_call_dunder_next_on_iterator ( iterator)
4676- . map ( TupleSpec :: homogeneous)
4680+ . map ( |ty| Cow :: Owned ( TupleSpec :: homogeneous ( ty ) ) )
46774681 . map_err (
46784682 |dunder_next_error| IterationError :: IterReturnsInvalidIterator {
46794683 iterator,
@@ -4697,10 +4701,10 @@ impl<'db> Type<'db> {
46974701 // and the type returned by the `__getitem__` method.
46984702 //
46994703 // No diagnostic is emitted; iteration will always succeed!
4700- TupleSpec :: homogeneous ( UnionType :: from_elements (
4704+ Cow :: Owned ( TupleSpec :: homogeneous ( UnionType :: from_elements (
47014705 db,
47024706 [ dunder_next_return, dunder_getitem_return_type] ,
4703- ) )
4707+ ) ) )
47044708 } )
47054709 . map_err ( |dunder_getitem_error| {
47064710 IterationError :: PossiblyUnboundIterAndGetitemError {
@@ -4724,7 +4728,7 @@ impl<'db> Type<'db> {
47244728
47254729 // There's no `__iter__` method. Try `__getitem__` instead...
47264730 Err ( CallDunderError :: MethodNotAvailable ) => try_call_dunder_getitem ( )
4727- . map ( TupleSpec :: homogeneous)
4731+ . map ( |ty| Cow :: Owned ( TupleSpec :: homogeneous ( ty ) ) )
47284732 . map_err (
47294733 |dunder_getitem_error| IterationError :: UnboundIterAndGetitemError {
47304734 dunder_getitem_error,
0 commit comments