@@ -26,6 +26,7 @@ use starlark_map::smallmap;
2626use crate :: callable:: Function ;
2727use crate :: class:: Class ;
2828use crate :: literal:: Lit ;
29+ use crate :: stdlib:: Stdlib ;
2930use crate :: tuple:: Tuple ;
3031use crate :: type_output:: DisplayOutput ;
3132use crate :: type_output:: OutputWithLocations ;
@@ -92,11 +93,19 @@ pub struct TypeDisplayContext<'a> {
9293 /// Should we display for IDE Hover? This makes type names more readable but less precise.
9394 hover : bool ,
9495 always_display_module_name : bool ,
96+ tuple_qname : Option < & ' a QName > ,
9597}
9698
9799impl < ' a > TypeDisplayContext < ' a > {
98100 pub fn new ( xs : & [ & ' a Type ] ) -> Self {
99- let mut res = Self :: default ( ) ;
101+ Self :: new_with_tuple ( xs, None )
102+ }
103+
104+ pub fn new_with_tuple ( xs : & [ & ' a Type ] , tuple_qname : Option < & ' a QName > ) -> Self {
105+ let mut res = Self {
106+ tuple_qname,
107+ ..Self :: default ( )
108+ } ;
100109 for x in xs {
101110 res. add ( x) ;
102111 }
@@ -120,6 +129,10 @@ impl<'a> TypeDisplayContext<'a> {
120129 } )
121130 }
122131
132+ pub ( crate ) fn tuple_qname ( & self ) -> Option < & ' a QName > {
133+ self . tuple_qname
134+ }
135+
123136 /// Force that we always display at least the module name for qualified names.
124137 pub fn always_display_module_name ( & mut self ) {
125138 // We pretend that every qname is also in a fake module, and thus requires disambiguating.
@@ -786,7 +799,21 @@ impl Type {
786799 }
787800
788801 pub fn get_types_with_locations ( & self ) -> Vec < ( String , Option < TextRangeWithModule > ) > {
789- let ctx = TypeDisplayContext :: new ( & [ self ] ) ;
802+ self . get_types_with_locations_with_tuple_qname ( None )
803+ }
804+
805+ pub fn get_types_with_locations_with_stdlib (
806+ & self ,
807+ stdlib : & Stdlib ,
808+ ) -> Vec < ( String , Option < TextRangeWithModule > ) > {
809+ self . get_types_with_locations_with_tuple_qname ( Some ( stdlib. tuple_object ( ) . qname ( ) ) )
810+ }
811+
812+ fn get_types_with_locations_with_tuple_qname (
813+ & self ,
814+ tuple_qname : Option < & QName > ,
815+ ) -> Vec < ( String , Option < TextRangeWithModule > ) > {
816+ let ctx = TypeDisplayContext :: new_with_tuple ( & [ self ] , tuple_qname) ;
790817 let mut output = OutputWithLocations :: new ( & ctx) ;
791818 ctx. fmt_helper_generic ( self , false , & mut output) . unwrap ( ) ;
792819 output. parts ( ) . to_vec ( )
@@ -1661,6 +1688,15 @@ def overloaded_func[T](
16611688 output. parts ( ) . to_vec ( )
16621689 }
16631690
1691+ fn get_parts_with_tuple_qname (
1692+ t : & Type ,
1693+ tuple_qname : & pyrefly_python:: qname:: QName ,
1694+ ) -> Vec < ( String , Option < TextRangeWithModule > ) > {
1695+ let ctx = TypeDisplayContext :: new_with_tuple ( & [ t] , Some ( tuple_qname) ) ;
1696+ let output = ctx. get_types_with_location ( t, false ) ;
1697+ output. parts ( ) . to_vec ( )
1698+ }
1699+
16641700 fn parts_to_string ( parts : & [ ( String , Option < TextRangeWithModule > ) ] ) -> String {
16651701 parts. iter ( ) . map ( |( s, _) | s. as_str ( ) ) . collect :: < String > ( )
16661702 }
@@ -1865,20 +1901,25 @@ def overloaded_func[T](
18651901 let bar = fake_class ( "Bar" , "test" , 55 ) ;
18661902 let foo_type = Type :: ClassType ( ClassType :: new ( foo, TArgs :: default ( ) ) ) ;
18671903 let bar_type = Type :: ClassType ( ClassType :: new ( bar, TArgs :: default ( ) ) ) ;
1904+ let tuple_cls = fake_class ( "tuple" , "builtins" , 5 ) ;
18681905
18691906 // Test concrete tuple: tuple[Foo, Bar]
18701907 let concrete_tuple = Type :: Tuple ( Tuple :: Concrete ( vec ! [ foo_type. clone( ) , bar_type. clone( ) ] ) ) ;
18711908 let parts = get_parts ( & concrete_tuple) ;
18721909 for expected in & [ "tuple" , "Foo" , "Bar" ] {
18731910 assert_output_contains ( & parts, expected) ;
18741911 }
1912+ let parts_with_location = get_parts_with_tuple_qname ( & concrete_tuple, tuple_cls. qname ( ) ) ;
1913+ assert_part_has_location ( & parts_with_location, "tuple" , "builtins" , 5 ) ;
18751914
18761915 // Test unbounded tuple: tuple[Foo, ...]
18771916 let unbounded_tuple = Type :: Tuple ( Tuple :: Unbounded ( Box :: new ( foo_type) ) ) ;
18781917 let parts2 = get_parts ( & unbounded_tuple) ;
18791918 for expected in & [ "tuple" , "Foo" , "..." ] {
18801919 assert_output_contains ( & parts2, expected) ;
18811920 }
1921+ let parts_unbounded = get_parts_with_tuple_qname ( & unbounded_tuple, tuple_cls. qname ( ) ) ;
1922+ assert_part_has_location ( & parts_unbounded, "tuple" , "builtins" , 5 ) ;
18821923 }
18831924
18841925 #[ test]
0 commit comments