@@ -6,28 +6,42 @@ use crate::{
6
6
db:: HirDatabase , utils:: generics, ApplicationTy , CallableDef , FnSig , GenericPredicate ,
7
7
Obligation , ProjectionTy , Substs , TraitRef , Ty , TypeCtor ,
8
8
} ;
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
+ } ;
10
13
use hir_expand:: name:: Name ;
11
14
12
- pub struct HirFormatter < ' a , ' b > {
15
+ pub struct HirFormatter < ' a > {
13
16
pub db : & ' a dyn HirDatabase ,
14
- fmt : & ' a mut fmt:: Formatter < ' b > ,
17
+ fmt : & ' a mut dyn fmt:: Write ,
15
18
buf : String ,
16
19
curr_size : usize ,
17
20
pub ( crate ) max_size : Option < usize > ,
18
21
omit_verbose_types : bool ,
22
+ display_target : DisplayTarget ,
19
23
}
20
24
21
25
pub trait HirDisplay {
22
- fn hir_fmt ( & self , f : & mut HirFormatter ) -> fmt :: Result ;
26
+ fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > ;
23
27
28
+ /// Returns a `Display`able type that is human-readable.
29
+ /// Use this for showing types to the user (e.g. diagnostics)
24
30
fn display < ' a > ( & ' a self , db : & ' a dyn HirDatabase ) -> HirDisplayWrapper < ' a , Self >
25
31
where
26
32
Self : Sized ,
27
33
{
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
+ }
29
41
}
30
42
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)
31
45
fn display_truncated < ' a > (
32
46
& ' a self ,
33
47
db : & ' a dyn HirDatabase ,
@@ -36,16 +50,46 @@ pub trait HirDisplay {
36
50
where
37
51
Self : Sized ,
38
52
{
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)
40
84
}
41
85
}
42
86
43
- impl < ' a , ' b > HirFormatter < ' a , ' b > {
87
+ impl < ' a > HirFormatter < ' a > {
44
88
pub fn write_joined < T : HirDisplay > (
45
89
& mut self ,
46
90
iter : impl IntoIterator < Item = T > ,
47
91
sep : & str ,
48
- ) -> fmt :: Result {
92
+ ) -> Result < ( ) , HirDisplayError > {
49
93
let mut first = true ;
50
94
for e in iter {
51
95
if !first {
@@ -58,14 +102,14 @@ impl<'a, 'b> HirFormatter<'a, 'b> {
58
102
}
59
103
60
104
/// 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 > {
62
106
// We write to a buffer first to track output size
63
107
self . buf . clear ( ) ;
64
108
fmt:: write ( & mut self . buf , args) ?;
65
109
self . curr_size += self . buf . len ( ) ;
66
110
67
111
// 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 )
69
113
}
70
114
71
115
pub fn should_truncate ( & self ) -> bool {
@@ -81,34 +125,76 @@ impl<'a, 'b> HirFormatter<'a, 'b> {
81
125
}
82
126
}
83
127
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
+ }
85
163
86
164
impl < ' a , T > fmt:: Display for HirDisplayWrapper < ' a , T >
87
165
where
88
166
T : HirDisplay ,
89
167
{
90
168
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 ,
93
171
fmt : f,
94
172
buf : String :: with_capacity ( 20 ) ,
95
173
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
+ }
99
185
}
100
186
}
101
187
102
188
const TYPE_HINT_TRUNCATION : & str = "…" ;
103
189
104
190
impl HirDisplay for & Ty {
105
- fn hir_fmt ( & self , f : & mut HirFormatter ) -> fmt :: Result {
191
+ fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
106
192
HirDisplay :: hir_fmt ( * self , f)
107
193
}
108
194
}
109
195
110
196
impl HirDisplay for ApplicationTy {
111
- fn hir_fmt ( & self , f : & mut HirFormatter ) -> fmt :: Result {
197
+ fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
112
198
if f. should_truncate ( ) {
113
199
return write ! ( f, "{}" , TYPE_HINT_TRUNCATION ) ;
114
200
}
@@ -191,12 +277,30 @@ impl HirDisplay for ApplicationTy {
191
277
}
192
278
}
193
279
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
+
200
304
if self . parameters . len ( ) > 0 {
201
305
let mut non_default_parameters = Vec :: with_capacity ( self . parameters . len ( ) ) ;
202
306
let parameters_to_write = if f. omit_verbose_types ( ) {
@@ -269,7 +373,7 @@ impl HirDisplay for ApplicationTy {
269
373
}
270
374
271
375
impl HirDisplay for ProjectionTy {
272
- fn hir_fmt ( & self , f : & mut HirFormatter ) -> fmt :: Result {
376
+ fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
273
377
if f. should_truncate ( ) {
274
378
return write ! ( f, "{}" , TYPE_HINT_TRUNCATION ) ;
275
379
}
@@ -287,7 +391,7 @@ impl HirDisplay for ProjectionTy {
287
391
}
288
392
289
393
impl HirDisplay for Ty {
290
- fn hir_fmt ( & self , f : & mut HirFormatter ) -> fmt :: Result {
394
+ fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
291
395
if f. should_truncate ( ) {
292
396
return write ! ( f, "{}" , TYPE_HINT_TRUNCATION ) ;
293
397
}
@@ -332,7 +436,7 @@ impl HirDisplay for Ty {
332
436
fn write_bounds_like_dyn_trait (
333
437
predicates : & [ GenericPredicate ] ,
334
438
f : & mut HirFormatter ,
335
- ) -> fmt :: Result {
439
+ ) -> Result < ( ) , HirDisplayError > {
336
440
// Note: This code is written to produce nice results (i.e.
337
441
// corresponding to surface Rust) for types that can occur in
338
442
// actual Rust. It will have weird results if the predicates
@@ -394,7 +498,7 @@ fn write_bounds_like_dyn_trait(
394
498
}
395
499
396
500
impl 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 > {
398
502
if f. should_truncate ( ) {
399
503
return write ! ( f, "{}" , TYPE_HINT_TRUNCATION ) ;
400
504
}
@@ -416,19 +520,19 @@ impl TraitRef {
416
520
}
417
521
418
522
impl HirDisplay for TraitRef {
419
- fn hir_fmt ( & self , f : & mut HirFormatter ) -> fmt :: Result {
523
+ fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
420
524
self . hir_fmt_ext ( f, false )
421
525
}
422
526
}
423
527
424
528
impl HirDisplay for & GenericPredicate {
425
- fn hir_fmt ( & self , f : & mut HirFormatter ) -> fmt :: Result {
529
+ fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
426
530
HirDisplay :: hir_fmt ( * self , f)
427
531
}
428
532
}
429
533
430
534
impl HirDisplay for GenericPredicate {
431
- fn hir_fmt ( & self , f : & mut HirFormatter ) -> fmt :: Result {
535
+ fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
432
536
if f. should_truncate ( ) {
433
537
return write ! ( f, "{}" , TYPE_HINT_TRUNCATION ) ;
434
538
}
@@ -452,15 +556,15 @@ impl HirDisplay for GenericPredicate {
452
556
}
453
557
454
558
impl 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) ) ? ,
458
562
Obligation :: Projection ( proj) => write ! (
459
563
f,
460
564
"Normalize({} => {})" ,
461
565
proj. projection_ty. display( f. db) ,
462
566
proj. ty. display( f. db)
463
- ) ,
464
- }
567
+ ) ? ,
568
+ } )
465
569
}
466
570
}
0 commit comments