@@ -6,28 +6,42 @@ use crate::{
66 db:: HirDatabase , utils:: generics, ApplicationTy , CallableDef , FnSig , GenericPredicate ,
77 Obligation , ProjectionTy , Substs , TraitRef , Ty , TypeCtor ,
88} ;
9- use hir_def:: { generics:: TypeParamProvenance , AdtId , AssocContainerId , Lookup } ;
9+ use hir_def:: {
10+ find_path, generics:: TypeParamProvenance , item_scope:: ItemInNs , AdtId , AssocContainerId ,
11+ Lookup , ModuleId ,
12+ } ;
1013use hir_expand:: name:: Name ;
1114
12- pub struct HirFormatter < ' a , ' b > {
15+ pub struct HirFormatter < ' a > {
1316 pub db : & ' a dyn HirDatabase ,
14- fmt : & ' a mut fmt:: Formatter < ' b > ,
17+ fmt : & ' a mut dyn fmt:: Write ,
1518 buf : String ,
1619 curr_size : usize ,
1720 pub ( crate ) max_size : Option < usize > ,
1821 omit_verbose_types : bool ,
22+ display_target : DisplayTarget ,
1923}
2024
2125pub trait HirDisplay {
22- fn hir_fmt ( & self , f : & mut HirFormatter ) -> fmt :: Result ;
26+ fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > ;
2327
28+ /// Returns a `Display`able type that is human-readable.
29+ /// Use this for showing types to the user (e.g. diagnostics)
2430 fn display < ' a > ( & ' a self , db : & ' a dyn HirDatabase ) -> HirDisplayWrapper < ' a , Self >
2531 where
2632 Self : Sized ,
2733 {
28- HirDisplayWrapper ( db, self , None , false )
34+ HirDisplayWrapper {
35+ db,
36+ t : self ,
37+ max_size : None ,
38+ omit_verbose_types : false ,
39+ display_target : DisplayTarget :: Diagnostics ,
40+ }
2941 }
3042
43+ /// Returns a `Display`able type that is human-readable and tries to be succinct.
44+ /// Use this for showing types to the user where space is constrained (e.g. doc popups)
3145 fn display_truncated < ' a > (
3246 & ' a self ,
3347 db : & ' a dyn HirDatabase ,
@@ -36,16 +50,46 @@ pub trait HirDisplay {
3650 where
3751 Self : Sized ,
3852 {
39- HirDisplayWrapper ( db, self , max_size, true )
53+ HirDisplayWrapper {
54+ db,
55+ t : self ,
56+ max_size,
57+ omit_verbose_types : true ,
58+ display_target : DisplayTarget :: Diagnostics ,
59+ }
60+ }
61+
62+ /// Returns a String representation of `self` that can be inserted into the given module.
63+ /// Use this when generating code (e.g. assists)
64+ fn display_source_code < ' a > (
65+ & ' a self ,
66+ db : & ' a dyn HirDatabase ,
67+ module_id : ModuleId ,
68+ ) -> Result < String , DisplaySourceCodeError > {
69+ let mut result = String :: new ( ) ;
70+ match self . hir_fmt ( & mut HirFormatter {
71+ db,
72+ fmt : & mut result,
73+ buf : String :: with_capacity ( 20 ) ,
74+ curr_size : 0 ,
75+ max_size : None ,
76+ omit_verbose_types : false ,
77+ display_target : DisplayTarget :: SourceCode { module_id } ,
78+ } ) {
79+ Ok ( ( ) ) => { }
80+ Err ( HirDisplayError :: FmtError ) => panic ! ( "Writing to String can't fail!" ) ,
81+ Err ( HirDisplayError :: DisplaySourceCodeError ( e) ) => return Err ( e) ,
82+ } ;
83+ Ok ( result)
4084 }
4185}
4286
43- impl < ' a , ' b > HirFormatter < ' a , ' b > {
87+ impl < ' a > HirFormatter < ' a > {
4488 pub fn write_joined < T : HirDisplay > (
4589 & mut self ,
4690 iter : impl IntoIterator < Item = T > ,
4791 sep : & str ,
48- ) -> fmt :: Result {
92+ ) -> Result < ( ) , HirDisplayError > {
4993 let mut first = true ;
5094 for e in iter {
5195 if !first {
@@ -58,14 +102,14 @@ impl<'a, 'b> HirFormatter<'a, 'b> {
58102 }
59103
60104 /// This allows using the `write!` macro directly with a `HirFormatter`.
61- pub fn write_fmt ( & mut self , args : fmt:: Arguments ) -> fmt :: Result {
105+ pub fn write_fmt ( & mut self , args : fmt:: Arguments ) -> Result < ( ) , HirDisplayError > {
62106 // We write to a buffer first to track output size
63107 self . buf . clear ( ) ;
64108 fmt:: write ( & mut self . buf , args) ?;
65109 self . curr_size += self . buf . len ( ) ;
66110
67111 // Then we write to the internal formatter from the buffer
68- self . fmt . write_str ( & self . buf )
112+ self . fmt . write_str ( & self . buf ) . map_err ( HirDisplayError :: from )
69113 }
70114
71115 pub fn should_truncate ( & self ) -> bool {
@@ -81,34 +125,76 @@ impl<'a, 'b> HirFormatter<'a, 'b> {
81125 }
82126}
83127
84- pub struct HirDisplayWrapper < ' a , T > ( & ' a dyn HirDatabase , & ' a T , Option < usize > , bool ) ;
128+ #[ derive( Clone , Copy ) ]
129+ enum DisplayTarget {
130+ /// Display types for inlays, doc popups, autocompletion, etc...
131+ /// Showing `{unknown}` or not qualifying paths is fine here.
132+ /// There's no reason for this to fail.
133+ Diagnostics ,
134+ /// Display types for inserting them in source files.
135+ /// The generated code should compile, so paths need to be qualified.
136+ SourceCode { module_id : ModuleId } ,
137+ }
138+
139+ #[ derive( Debug ) ]
140+ pub enum DisplaySourceCodeError {
141+ PathNotFound ,
142+ }
143+
144+ pub enum HirDisplayError {
145+ /// Errors that can occur when generating source code
146+ DisplaySourceCodeError ( DisplaySourceCodeError ) ,
147+ /// `FmtError` is required to be compatible with std::fmt::Display
148+ FmtError ,
149+ }
150+ impl From < fmt:: Error > for HirDisplayError {
151+ fn from ( _: fmt:: Error ) -> Self {
152+ Self :: FmtError
153+ }
154+ }
155+
156+ pub struct HirDisplayWrapper < ' a , T > {
157+ db : & ' a dyn HirDatabase ,
158+ t : & ' a T ,
159+ max_size : Option < usize > ,
160+ omit_verbose_types : bool ,
161+ display_target : DisplayTarget ,
162+ }
85163
86164impl < ' a , T > fmt:: Display for HirDisplayWrapper < ' a , T >
87165where
88166 T : HirDisplay ,
89167{
90168 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
91- self . 1 . hir_fmt ( & mut HirFormatter {
92- db : self . 0 ,
169+ match self . t . hir_fmt ( & mut HirFormatter {
170+ db : self . db ,
93171 fmt : f,
94172 buf : String :: with_capacity ( 20 ) ,
95173 curr_size : 0 ,
96- max_size : self . 2 ,
97- omit_verbose_types : self . 3 ,
98- } )
174+ max_size : self . max_size ,
175+ omit_verbose_types : self . omit_verbose_types ,
176+ display_target : self . display_target ,
177+ } ) {
178+ Ok ( ( ) ) => Ok ( ( ) ) ,
179+ Err ( HirDisplayError :: FmtError ) => Err ( fmt:: Error ) ,
180+ Err ( HirDisplayError :: DisplaySourceCodeError ( _) ) => {
181+ // This should never happen
182+ panic ! ( "HirDisplay failed when calling Display::fmt!" )
183+ }
184+ }
99185 }
100186}
101187
102188const TYPE_HINT_TRUNCATION : & str = "…" ;
103189
104190impl HirDisplay for & Ty {
105- fn hir_fmt ( & self , f : & mut HirFormatter ) -> fmt :: Result {
191+ fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
106192 HirDisplay :: hir_fmt ( * self , f)
107193 }
108194}
109195
110196impl HirDisplay for ApplicationTy {
111- fn hir_fmt ( & self , f : & mut HirFormatter ) -> fmt :: Result {
197+ fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
112198 if f. should_truncate ( ) {
113199 return write ! ( f, "{}" , TYPE_HINT_TRUNCATION ) ;
114200 }
@@ -191,12 +277,30 @@ impl HirDisplay for ApplicationTy {
191277 }
192278 }
193279 TypeCtor :: Adt ( def_id) => {
194- let name = match def_id {
195- AdtId :: StructId ( it) => f. db . struct_data ( it) . name . clone ( ) ,
196- AdtId :: UnionId ( it) => f. db . union_data ( it) . name . clone ( ) ,
197- AdtId :: EnumId ( it) => f. db . enum_data ( it) . name . clone ( ) ,
198- } ;
199- write ! ( f, "{}" , name) ?;
280+ match f. display_target {
281+ DisplayTarget :: Diagnostics => {
282+ let name = match def_id {
283+ AdtId :: StructId ( it) => f. db . struct_data ( it) . name . clone ( ) ,
284+ AdtId :: UnionId ( it) => f. db . union_data ( it) . name . clone ( ) ,
285+ AdtId :: EnumId ( it) => f. db . enum_data ( it) . name . clone ( ) ,
286+ } ;
287+ write ! ( f, "{}" , name) ?;
288+ }
289+ DisplayTarget :: SourceCode { module_id } => {
290+ if let Some ( path) = find_path:: find_path (
291+ f. db . upcast ( ) ,
292+ ItemInNs :: Types ( def_id. into ( ) ) ,
293+ module_id,
294+ ) {
295+ write ! ( f, "{}" , path) ?;
296+ } else {
297+ return Err ( HirDisplayError :: DisplaySourceCodeError (
298+ DisplaySourceCodeError :: PathNotFound ,
299+ ) ) ;
300+ }
301+ }
302+ }
303+
200304 if self . parameters . len ( ) > 0 {
201305 let mut non_default_parameters = Vec :: with_capacity ( self . parameters . len ( ) ) ;
202306 let parameters_to_write = if f. omit_verbose_types ( ) {
@@ -269,7 +373,7 @@ impl HirDisplay for ApplicationTy {
269373}
270374
271375impl HirDisplay for ProjectionTy {
272- fn hir_fmt ( & self , f : & mut HirFormatter ) -> fmt :: Result {
376+ fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
273377 if f. should_truncate ( ) {
274378 return write ! ( f, "{}" , TYPE_HINT_TRUNCATION ) ;
275379 }
@@ -287,7 +391,7 @@ impl HirDisplay for ProjectionTy {
287391}
288392
289393impl HirDisplay for Ty {
290- fn hir_fmt ( & self , f : & mut HirFormatter ) -> fmt :: Result {
394+ fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
291395 if f. should_truncate ( ) {
292396 return write ! ( f, "{}" , TYPE_HINT_TRUNCATION ) ;
293397 }
@@ -332,7 +436,7 @@ impl HirDisplay for Ty {
332436fn write_bounds_like_dyn_trait (
333437 predicates : & [ GenericPredicate ] ,
334438 f : & mut HirFormatter ,
335- ) -> fmt :: Result {
439+ ) -> Result < ( ) , HirDisplayError > {
336440 // Note: This code is written to produce nice results (i.e.
337441 // corresponding to surface Rust) for types that can occur in
338442 // actual Rust. It will have weird results if the predicates
@@ -394,7 +498,7 @@ fn write_bounds_like_dyn_trait(
394498}
395499
396500impl TraitRef {
397- fn hir_fmt_ext ( & self , f : & mut HirFormatter , use_as : bool ) -> fmt :: Result {
501+ fn hir_fmt_ext ( & self , f : & mut HirFormatter , use_as : bool ) -> Result < ( ) , HirDisplayError > {
398502 if f. should_truncate ( ) {
399503 return write ! ( f, "{}" , TYPE_HINT_TRUNCATION ) ;
400504 }
@@ -416,19 +520,19 @@ impl TraitRef {
416520}
417521
418522impl HirDisplay for TraitRef {
419- fn hir_fmt ( & self , f : & mut HirFormatter ) -> fmt :: Result {
523+ fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
420524 self . hir_fmt_ext ( f, false )
421525 }
422526}
423527
424528impl HirDisplay for & GenericPredicate {
425- fn hir_fmt ( & self , f : & mut HirFormatter ) -> fmt :: Result {
529+ fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
426530 HirDisplay :: hir_fmt ( * self , f)
427531 }
428532}
429533
430534impl HirDisplay for GenericPredicate {
431- fn hir_fmt ( & self , f : & mut HirFormatter ) -> fmt :: Result {
535+ fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
432536 if f. should_truncate ( ) {
433537 return write ! ( f, "{}" , TYPE_HINT_TRUNCATION ) ;
434538 }
@@ -452,15 +556,15 @@ impl HirDisplay for GenericPredicate {
452556}
453557
454558impl HirDisplay for Obligation {
455- fn hir_fmt ( & self , f : & mut HirFormatter ) -> fmt :: Result {
456- match self {
457- Obligation :: Trait ( tr) => write ! ( f, "Implements({})" , tr. display( f. db) ) ,
559+ fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
560+ Ok ( match self {
561+ Obligation :: Trait ( tr) => write ! ( f, "Implements({})" , tr. display( f. db) ) ? ,
458562 Obligation :: Projection ( proj) => write ! (
459563 f,
460564 "Normalize({} => {})" ,
461565 proj. projection_ty. display( f. db) ,
462566 proj. ty. display( f. db)
463- ) ,
464- }
567+ ) ? ,
568+ } )
465569 }
466570}
0 commit comments