@@ -28,7 +28,7 @@ use intern::{Internable, Interned};
28
28
use itertools:: Itertools ;
29
29
use la_arena:: ArenaMap ;
30
30
use smallvec:: SmallVec ;
31
- use stdx:: never;
31
+ use stdx:: { never, IsNoneOr } ;
32
32
use triomphe:: Arc ;
33
33
34
34
use crate :: {
@@ -41,9 +41,9 @@ use crate::{
41
41
mir:: pad16,
42
42
primitive, to_assoc_type_id,
43
43
utils:: { self , detect_variant_from_bytes, generics, ClosureSubst } ,
44
- AdtId , AliasEq , AliasTy , Binders , CallableDefId , CallableSig , Const , ConstScalar , ConstValue ,
45
- DomainGoal , FnAbi , GenericArg , GenericArgData , ImplTraitId , Interner , Lifetime , LifetimeData ,
46
- LifetimeOutlives , MemoryMap , Mutability , OpaqueTy , ProjectionTy , ProjectionTyExt ,
44
+ AdtId , AliasEq , AliasTy , Binders , CallableDefId , CallableSig , ConcreteConst , Const ,
45
+ ConstScalar , ConstValue , DomainGoal , FnAbi , GenericArg , ImplTraitId , Interner , Lifetime ,
46
+ LifetimeData , LifetimeOutlives , MemoryMap , Mutability , OpaqueTy , ProjectionTy , ProjectionTyExt ,
47
47
QuantifiedWhereClause , Scalar , Substitution , TraitEnvironment , TraitRef , TraitRefExt , Ty ,
48
48
TyExt , WhereClause ,
49
49
} ;
@@ -60,11 +60,18 @@ impl HirWrite for String {}
60
60
impl HirWrite for fmt:: Formatter < ' _ > { }
61
61
62
62
pub struct HirFormatter < ' a > {
63
+ /// The database handle
63
64
pub db : & ' a dyn HirDatabase ,
65
+ /// The sink to write into
64
66
fmt : & ' a mut dyn HirWrite ,
67
+ /// A buffer to intercept writes with, this allows us to track the overall size of the formatted output.
65
68
buf : String ,
69
+ /// The current size of the formatted output.
66
70
curr_size : usize ,
67
- pub ( crate ) max_size : Option < usize > ,
71
+ /// Size from which we should truncate the output.
72
+ max_size : Option < usize > ,
73
+ /// When rendering something that has a concept of "children" (like fields in a struct), this limits
74
+ /// how many should be rendered.
68
75
pub entity_limit : Option < usize > ,
69
76
omit_verbose_types : bool ,
70
77
closure_style : ClosureStyle ,
@@ -304,7 +311,6 @@ impl DisplayTarget {
304
311
#[ derive( Debug ) ]
305
312
pub enum DisplaySourceCodeError {
306
313
PathNotFound ,
307
- UnknownType ,
308
314
Coroutine ,
309
315
OpaqueType ,
310
316
}
@@ -418,6 +424,7 @@ impl HirDisplay for ProjectionTy {
418
424
let proj_params = & self . substitution . as_slice ( Interner ) [ ..proj_params_count] ;
419
425
if !proj_params. is_empty ( ) {
420
426
write ! ( f, "<" ) ?;
427
+ // FIXME use `hir_fmt_generics` here
421
428
f. write_joined ( proj_params, ", " ) ?;
422
429
write ! ( f, ">" ) ?;
423
430
}
@@ -967,6 +974,7 @@ impl HirDisplay for Ty {
967
974
. chain ( fn_params)
968
975
. flatten ( ) ;
969
976
write ! ( f, "<" ) ?;
977
+ // FIXME use `hir_fmt_generics` here
970
978
f. write_joined ( params, ", " ) ?;
971
979
write ! ( f, ">" ) ?;
972
980
}
@@ -1037,6 +1045,7 @@ impl HirDisplay for Ty {
1037
1045
// FIXME: reconsider the generic args order upon formatting?
1038
1046
if parameters. len ( Interner ) > 0 {
1039
1047
write ! ( f, "<" ) ?;
1048
+ // FIXME use `hir_fmt_generics` here
1040
1049
f. write_joined ( parameters. as_slice ( Interner ) , ", " ) ?;
1041
1050
write ! ( f, ">" ) ?;
1042
1051
}
@@ -1287,11 +1296,10 @@ impl HirDisplay for Ty {
1287
1296
}
1288
1297
TyKind :: Error => {
1289
1298
if f. display_target . is_source_code ( ) {
1290
- return Err ( HirDisplayError :: DisplaySourceCodeError (
1291
- DisplaySourceCodeError :: UnknownType ,
1292
- ) ) ;
1299
+ f . write_char ( '_' ) ? ;
1300
+ } else {
1301
+ write ! ( f , "{{unknown}}" ) ? ;
1293
1302
}
1294
- write ! ( f, "{{unknown}}" ) ?;
1295
1303
}
1296
1304
TyKind :: InferenceVar ( ..) => write ! ( f, "_" ) ?,
1297
1305
TyKind :: Coroutine ( _, subst) => {
@@ -1331,98 +1339,90 @@ fn hir_fmt_generics(
1331
1339
parameters : & Substitution ,
1332
1340
generic_def : Option < hir_def:: GenericDefId > ,
1333
1341
) -> Result < ( ) , HirDisplayError > {
1334
- let db = f. db ;
1335
- if parameters. len ( Interner ) > 0 {
1336
- use std:: cmp:: Ordering ;
1337
- let param_compare =
1338
- |a : & GenericArg , b : & GenericArg | match ( a. data ( Interner ) , b. data ( Interner ) ) {
1339
- ( crate :: GenericArgData :: Lifetime ( _) , crate :: GenericArgData :: Lifetime ( _) ) => {
1340
- Ordering :: Equal
1341
- }
1342
- ( crate :: GenericArgData :: Lifetime ( _) , _) => Ordering :: Less ,
1343
- ( _, crate :: GenericArgData :: Lifetime ( _) ) => Ordering :: Less ,
1344
- ( _, _) => Ordering :: Equal ,
1345
- } ;
1346
- let parameters_to_write = if f. display_target . is_source_code ( ) || f. omit_verbose_types ( ) {
1347
- match generic_def
1348
- . map ( |generic_def_id| db. generic_defaults ( generic_def_id) )
1349
- . filter ( |defaults| !defaults. is_empty ( ) )
1350
- {
1351
- None => parameters. as_slice ( Interner ) ,
1352
- Some ( default_parameters) => {
1353
- fn should_show (
1354
- parameter : & GenericArg ,
1355
- default_parameters : & [ Binders < GenericArg > ] ,
1356
- i : usize ,
1357
- parameters : & Substitution ,
1358
- ) -> bool {
1359
- if parameter. ty ( Interner ) . map ( |it| it. kind ( Interner ) )
1360
- == Some ( & TyKind :: Error )
1361
- {
1362
- return true ;
1363
- }
1364
- if let Some ( ConstValue :: Concrete ( c) ) =
1365
- parameter. constant ( Interner ) . map ( |it| & it. data ( Interner ) . value )
1366
- {
1367
- if c. interned == ConstScalar :: Unknown {
1368
- return true ;
1369
- }
1370
- }
1371
- if let Some ( crate :: LifetimeData :: Static | crate :: LifetimeData :: Error ) =
1372
- parameter. lifetime ( Interner ) . map ( |it| it. data ( Interner ) )
1373
- {
1374
- return true ;
1342
+ if parameters. is_empty ( Interner ) {
1343
+ return Ok ( ( ) ) ;
1344
+ }
1345
+
1346
+ let parameters_to_write =
1347
+ generic_args_sans_defaults ( f, generic_def, parameters. as_slice ( Interner ) ) ;
1348
+ if !parameters_to_write. is_empty ( ) {
1349
+ write ! ( f, "<" ) ?;
1350
+ hir_fmt_generic_arguments ( f, parameters_to_write) ?;
1351
+ write ! ( f, ">" ) ?;
1352
+ }
1353
+
1354
+ Ok ( ( ) )
1355
+ }
1356
+
1357
+ fn generic_args_sans_defaults < ' ga > (
1358
+ f : & mut HirFormatter < ' _ > ,
1359
+ generic_def : Option < hir_def:: GenericDefId > ,
1360
+ parameters : & ' ga [ GenericArg ] ,
1361
+ ) -> & ' ga [ GenericArg ] {
1362
+ if f. display_target . is_source_code ( ) || f. omit_verbose_types ( ) {
1363
+ match generic_def
1364
+ . map ( |generic_def_id| f. db . generic_defaults ( generic_def_id) )
1365
+ . filter ( |it| !it. is_empty ( ) )
1366
+ {
1367
+ None => parameters,
1368
+ Some ( default_parameters) => {
1369
+ let should_show = |arg : & GenericArg , i : usize | {
1370
+ let is_err = |arg : & GenericArg | match arg. data ( Interner ) {
1371
+ chalk_ir:: GenericArgData :: Lifetime ( it) => {
1372
+ * it. data ( Interner ) == LifetimeData :: Error
1375
1373
}
1376
- let default_parameter = match default_parameters. get ( i) {
1377
- Some ( it) => it,
1378
- None => return true ,
1379
- } ;
1380
- let actual_default =
1381
- default_parameter. clone ( ) . substitute ( Interner , & parameters) ;
1382
- parameter != & actual_default
1374
+ chalk_ir:: GenericArgData :: Ty ( it) => * it. kind ( Interner ) == TyKind :: Error ,
1375
+ chalk_ir:: GenericArgData :: Const ( it) => matches ! (
1376
+ it. data( Interner ) . value,
1377
+ ConstValue :: Concrete ( ConcreteConst {
1378
+ interned: ConstScalar :: Unknown ,
1379
+ ..
1380
+ } )
1381
+ ) ,
1382
+ } ;
1383
+ // if the arg is error like, render it to inform the user
1384
+ if is_err ( arg) {
1385
+ return true ;
1383
1386
}
1384
- let mut default_from = 0 ;
1385
- for ( i, parameter) in parameters. iter ( Interner ) . enumerate ( ) {
1386
- if should_show ( parameter, & default_parameters, i, parameters) {
1387
- default_from = i + 1 ;
1388
- }
1387
+ // otherwise, if the arg is equal to the param default, hide it (unless the
1388
+ // default is an error which can happen for the trait Self type)
1389
+ default_parameters. get ( i) . is_none_or ( |default_parameter| {
1390
+ // !is_err(default_parameter.skip_binders())
1391
+ // &&
1392
+ arg != & default_parameter. clone ( ) . substitute ( Interner , & parameters)
1393
+ } )
1394
+ } ;
1395
+ let mut default_from = 0 ;
1396
+ for ( i, parameter) in parameters. iter ( ) . enumerate ( ) {
1397
+ if should_show ( parameter, i) {
1398
+ default_from = i + 1 ;
1389
1399
}
1390
- & parameters. as_slice ( Interner ) [ 0 ..default_from]
1391
- }
1392
- }
1393
- } else {
1394
- parameters. as_slice ( Interner )
1395
- } ;
1396
- //FIXME: Should handle the ordering of lifetimes when creating substitutions
1397
- let mut parameters_to_write = parameters_to_write. to_vec ( ) ;
1398
- parameters_to_write. sort_by ( param_compare) ;
1399
- if !parameters_to_write. is_empty ( ) {
1400
- write ! ( f, "<" ) ?;
1401
- let mut first = true ;
1402
- for generic_arg in parameters_to_write {
1403
- if !first {
1404
- write ! ( f, ", " ) ?;
1405
- }
1406
- first = false ;
1407
- if f. display_target . is_source_code ( ) {
1408
- match generic_arg. data ( Interner ) {
1409
- GenericArgData :: Lifetime ( l)
1410
- if matches ! ( l. data( Interner ) , LifetimeData :: Error ) =>
1411
- {
1412
- write ! ( f, "'_" )
1413
- }
1414
- GenericArgData :: Ty ( t) if matches ! ( t. kind( Interner ) , TyKind :: Error ) => {
1415
- write ! ( f, "_" )
1416
- }
1417
- _ => generic_arg. hir_fmt ( f) ,
1418
- } ?
1419
- } else {
1420
- generic_arg. hir_fmt ( f) ?;
1421
1400
}
1401
+ & parameters[ 0 ..default_from]
1422
1402
}
1403
+ }
1404
+ } else {
1405
+ parameters
1406
+ }
1407
+ }
1423
1408
1424
- write ! ( f, ">" ) ?;
1409
+ fn hir_fmt_generic_arguments (
1410
+ f : & mut HirFormatter < ' _ > ,
1411
+ parameters : & [ GenericArg ] ,
1412
+ ) -> Result < ( ) , HirDisplayError > {
1413
+ let mut first = true ;
1414
+ let lifetime_offset = parameters. iter ( ) . position ( |arg| arg. lifetime ( Interner ) . is_some ( ) ) ;
1415
+
1416
+ let ( ty_or_const, lifetimes) = match lifetime_offset {
1417
+ Some ( offset) => parameters. split_at ( offset) ,
1418
+ None => ( parameters, & [ ] [ ..] ) ,
1419
+ } ;
1420
+ for generic_arg in lifetimes. iter ( ) . chain ( ty_or_const) {
1421
+ if !first {
1422
+ write ! ( f, ", " ) ?;
1425
1423
}
1424
+ first = false ;
1425
+ generic_arg. hir_fmt ( f) ?;
1426
1426
}
1427
1427
Ok ( ( ) )
1428
1428
}
@@ -1544,20 +1544,29 @@ fn write_bounds_like_dyn_trait(
1544
1544
f. start_location_link ( trait_. into ( ) ) ;
1545
1545
write ! ( f, "{}" , f. db. trait_data( trait_) . name. display( f. db. upcast( ) ) ) ?;
1546
1546
f. end_location_link ( ) ;
1547
- if let [ _ , params @ .. ] = trait_ref . substitution . as_slice ( Interner ) {
1548
- if is_fn_trait {
1547
+ if is_fn_trait {
1548
+ if let [ _self , params @ .. ] = trait_ref . substitution . as_slice ( Interner ) {
1549
1549
if let Some ( args) =
1550
1550
params. first ( ) . and_then ( |it| it. assert_ty_ref ( Interner ) . as_tuple ( ) )
1551
1551
{
1552
1552
write ! ( f, "(" ) ?;
1553
- f . write_joined ( args. as_slice ( Interner ) , ", " ) ?;
1553
+ hir_fmt_generic_arguments ( f , args. as_slice ( Interner ) ) ?;
1554
1554
write ! ( f, ")" ) ?;
1555
1555
}
1556
- } else if !params. is_empty ( ) {
1557
- write ! ( f, "<" ) ?;
1558
- f. write_joined ( params, ", " ) ?;
1559
- // there might be assoc type bindings, so we leave the angle brackets open
1560
- angle_open = true ;
1556
+ }
1557
+ } else {
1558
+ let params = generic_args_sans_defaults (
1559
+ f,
1560
+ Some ( trait_. into ( ) ) ,
1561
+ trait_ref. substitution . as_slice ( Interner ) ,
1562
+ ) ;
1563
+ if let [ _self, params @ ..] = params {
1564
+ if !params. is_empty ( ) {
1565
+ write ! ( f, "<" ) ?;
1566
+ hir_fmt_generic_arguments ( f, params) ?;
1567
+ // there might be assoc type bindings, so we leave the angle brackets open
1568
+ angle_open = true ;
1569
+ }
1561
1570
}
1562
1571
}
1563
1572
}
@@ -1609,9 +1618,9 @@ fn write_bounds_like_dyn_trait(
1609
1618
let proj_arg_count = generics ( f. db . upcast ( ) , assoc_ty_id. into ( ) ) . len_self ( ) ;
1610
1619
if proj_arg_count > 0 {
1611
1620
write ! ( f, "<" ) ?;
1612
- f. write_joined (
1621
+ hir_fmt_generic_arguments (
1622
+ f,
1613
1623
& proj. substitution . as_slice ( Interner ) [ ..proj_arg_count] ,
1614
- ", " ,
1615
1624
) ?;
1616
1625
write ! ( f, ">" ) ?;
1617
1626
}
@@ -1670,6 +1679,7 @@ fn fmt_trait_ref(
1670
1679
f. end_location_link ( ) ;
1671
1680
if tr. substitution . len ( Interner ) > 1 {
1672
1681
write ! ( f, "<" ) ?;
1682
+ // FIXME use `hir_fmt_generics` here
1673
1683
f. write_joined ( & tr. substitution . as_slice ( Interner ) [ 1 ..] , ", " ) ?;
1674
1684
write ! ( f, ">" ) ?;
1675
1685
}
@@ -1728,15 +1738,16 @@ impl HirDisplay for Lifetime {
1728
1738
impl HirDisplay for LifetimeData {
1729
1739
fn hir_fmt ( & self , f : & mut HirFormatter < ' _ > ) -> Result < ( ) , HirDisplayError > {
1730
1740
match self {
1731
- LifetimeData :: BoundVar ( idx) => idx. hir_fmt ( f) ,
1732
- LifetimeData :: InferenceVar ( _) => write ! ( f, "_" ) ,
1733
1741
LifetimeData :: Placeholder ( idx) => {
1734
1742
let id = lt_from_placeholder_idx ( f. db , * idx) ;
1735
1743
let generics = generics ( f. db . upcast ( ) , id. parent ) ;
1736
1744
let param_data = & generics. params [ id. local_id ] ;
1737
1745
write ! ( f, "{}" , param_data. name. display( f. db. upcast( ) ) ) ?;
1738
1746
Ok ( ( ) )
1739
1747
}
1748
+ _ if f. display_target . is_source_code ( ) => write ! ( f, "'_" ) ,
1749
+ LifetimeData :: BoundVar ( idx) => idx. hir_fmt ( f) ,
1750
+ LifetimeData :: InferenceVar ( _) => write ! ( f, "_" ) ,
1740
1751
LifetimeData :: Static => write ! ( f, "'static" ) ,
1741
1752
LifetimeData :: Error => write ! ( f, "'{{error}}" ) ,
1742
1753
LifetimeData :: Erased => Ok ( ( ) ) ,
0 commit comments