2019-09-30 03:58:53 -05:00
//! FIXME: write short doc here
2021-01-12 13:19:13 -06:00
use std ::{ borrow ::Cow , fmt } ;
2019-03-14 16:03:39 -05:00
2021-01-12 13:19:13 -06:00
use arrayvec ::ArrayVec ;
2021-03-01 12:30:34 -06:00
use chalk_ir ::Mutability ;
2020-04-25 09:57:59 -05:00
use hir_def ::{
2021-03-14 07:03:39 -05:00
db ::DefDatabase ,
find_path ,
generics ::TypeParamProvenance ,
item_scope ::ItemInNs ,
path ::{ GenericArg , Path , PathKind } ,
type_ref ::{ TypeBound , TypeRef } ,
visibility ::Visibility ,
2021-03-09 12:09:02 -06:00
AssocContainerId , Lookup , ModuleId , TraitId ,
2020-04-25 09:57:59 -05:00
} ;
2020-02-14 08:01:25 -06:00
use hir_expand ::name ::Name ;
2019-03-14 16:03:39 -05:00
2021-03-01 14:57:39 -06:00
use crate ::{
2021-03-13 12:47:34 -06:00
db ::HirDatabase , from_assoc_type_id , from_foreign_def_id , from_placeholder_idx , primitive ,
to_assoc_type_id , traits ::chalk ::from_chalk , utils ::generics , AdtId , AliasTy , CallableDefId ,
2021-03-13 13:05:47 -06:00
CallableSig , GenericPredicate , ImplTraitId , Interner , Lifetime , Obligation , OpaqueTy ,
2021-03-15 15:02:34 -05:00
ProjectionTy , Scalar , Substitution , TraitRef , Ty , TyKind ,
2021-03-01 14:57:39 -06:00
} ;
2020-04-25 09:57:59 -05:00
pub struct HirFormatter < ' a > {
2020-03-13 10:05:46 -05:00
pub db : & ' a dyn HirDatabase ,
2020-04-25 09:57:59 -05:00
fmt : & ' a mut dyn fmt ::Write ,
2019-11-18 11:02:28 -06:00
buf : String ,
curr_size : usize ,
2020-01-22 08:44:05 -06:00
pub ( crate ) max_size : Option < usize > ,
2019-12-23 09:53:35 -06:00
omit_verbose_types : bool ,
2020-04-25 09:57:59 -05:00
display_target : DisplayTarget ,
2019-03-14 16:03:39 -05:00
}
pub trait HirDisplay {
2020-04-25 09:57:59 -05:00
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > ;
2019-11-18 11:02:28 -06:00
2020-10-28 11:58:16 -05:00
/// Returns a `Display`able type that is human-readable.
fn into_displayable < ' a > (
& ' a self ,
db : & ' a dyn HirDatabase ,
max_size : Option < usize > ,
omit_verbose_types : bool ,
display_target : DisplayTarget ,
) -> HirDisplayWrapper < ' a , Self >
where
Self : Sized ,
{
HirDisplayWrapper { db , t : self , max_size , omit_verbose_types , display_target }
}
2020-04-25 09:57:59 -05:00
/// Returns a `Display`able type that is human-readable.
/// Use this for showing types to the user (e.g. diagnostics)
2020-03-13 10:05:46 -05:00
fn display < ' a > ( & ' a self , db : & ' a dyn HirDatabase ) -> HirDisplayWrapper < ' a , Self >
2019-03-14 16:03:39 -05:00
where
Self : Sized ,
{
2020-04-25 09:57:59 -05:00
HirDisplayWrapper {
db ,
t : self ,
max_size : None ,
omit_verbose_types : false ,
display_target : DisplayTarget ::Diagnostics ,
}
2019-11-18 11:02:28 -06:00
}
2020-04-25 09:57:59 -05:00
/// Returns a `Display`able type that is human-readable and tries to be succinct.
/// Use this for showing types to the user where space is constrained (e.g. doc popups)
2020-03-13 10:05:46 -05:00
fn display_truncated < ' a > (
2019-11-18 11:02:28 -06:00
& ' a self ,
2020-03-13 10:05:46 -05:00
db : & ' a dyn HirDatabase ,
2019-12-19 08:43:41 -06:00
max_size : Option < usize > ,
2020-03-13 10:05:46 -05:00
) -> HirDisplayWrapper < ' a , Self >
2019-11-18 11:02:28 -06:00
where
Self : Sized ,
{
2020-04-25 09:57:59 -05:00
HirDisplayWrapper {
db ,
t : self ,
max_size ,
omit_verbose_types : true ,
display_target : DisplayTarget ::Diagnostics ,
}
}
/// Returns a String representation of `self` that can be inserted into the given module.
/// Use this when generating code (e.g. assists)
fn display_source_code < ' a > (
& ' a self ,
db : & ' a dyn HirDatabase ,
module_id : ModuleId ,
) -> Result < String , DisplaySourceCodeError > {
let mut result = String ::new ( ) ;
match self . hir_fmt ( & mut HirFormatter {
db ,
fmt : & mut result ,
buf : String ::with_capacity ( 20 ) ,
curr_size : 0 ,
max_size : None ,
omit_verbose_types : false ,
display_target : DisplayTarget ::SourceCode { module_id } ,
2020-10-28 06:29:42 -05:00
} ) {
Ok ( ( ) ) = > { }
Err ( HirDisplayError ::FmtError ) = > panic! ( " Writing to String can't fail! " ) ,
Err ( HirDisplayError ::DisplaySourceCodeError ( e ) ) = > return Err ( e ) ,
} ;
Ok ( result )
}
/// Returns a String representation of `self` for test purposes
2020-10-28 09:09:47 -05:00
fn display_test < ' a > ( & ' a self , db : & ' a dyn HirDatabase ) -> HirDisplayWrapper < ' a , Self >
where
Self : Sized ,
{
HirDisplayWrapper {
2020-10-28 06:29:42 -05:00
db ,
2020-10-28 09:09:47 -05:00
t : self ,
2020-10-28 06:29:42 -05:00
max_size : None ,
omit_verbose_types : false ,
2020-10-28 09:09:47 -05:00
display_target : DisplayTarget ::Test ,
}
2019-03-14 16:03:39 -05:00
}
}
2020-04-25 09:57:59 -05:00
impl < ' a > HirFormatter < ' a > {
2019-03-14 16:03:39 -05:00
pub fn write_joined < T : HirDisplay > (
& mut self ,
iter : impl IntoIterator < Item = T > ,
sep : & str ,
2020-04-25 09:57:59 -05:00
) -> Result < ( ) , HirDisplayError > {
2019-03-14 16:03:39 -05:00
let mut first = true ;
for e in iter {
if ! first {
write! ( self , " {} " , sep ) ? ;
}
first = false ;
e . hir_fmt ( self ) ? ;
}
Ok ( ( ) )
}
/// This allows using the `write!` macro directly with a `HirFormatter`.
2020-04-25 09:57:59 -05:00
pub fn write_fmt ( & mut self , args : fmt ::Arguments ) -> Result < ( ) , HirDisplayError > {
2019-11-18 11:02:28 -06:00
// We write to a buffer first to track output size
self . buf . clear ( ) ;
fmt ::write ( & mut self . buf , args ) ? ;
self . curr_size + = self . buf . len ( ) ;
// Then we write to the internal formatter from the buffer
2020-04-25 09:57:59 -05:00
self . fmt . write_str ( & self . buf ) . map_err ( HirDisplayError ::from )
2019-11-18 11:02:28 -06:00
}
pub fn should_truncate ( & self ) -> bool {
2019-12-19 08:43:41 -06:00
if let Some ( max_size ) = self . max_size {
2019-11-18 11:02:28 -06:00
self . curr_size > = max_size
} else {
false
}
2019-03-14 16:03:39 -05:00
}
2019-12-07 16:54:18 -06:00
2019-12-23 09:53:35 -06:00
pub fn omit_verbose_types ( & self ) -> bool {
self . omit_verbose_types
2019-12-07 16:54:18 -06:00
}
}
2020-04-25 09:57:59 -05:00
#[ derive(Clone, Copy) ]
2020-10-28 11:58:16 -05:00
pub enum DisplayTarget {
2020-04-25 09:57:59 -05:00
/// Display types for inlays, doc popups, autocompletion, etc...
/// Showing `{unknown}` or not qualifying paths is fine here.
/// There's no reason for this to fail.
Diagnostics ,
/// Display types for inserting them in source files.
/// The generated code should compile, so paths need to be qualified.
SourceCode { module_id : ModuleId } ,
2020-10-28 05:20:05 -05:00
/// Only for test purpose to keep real types
2020-10-28 09:09:47 -05:00
Test ,
2020-04-25 09:57:59 -05:00
}
2020-05-10 11:09:22 -05:00
impl DisplayTarget {
fn is_source_code ( & self ) -> bool {
2021-01-05 06:45:46 -06:00
matches! ( self , Self ::SourceCode { .. } )
2020-05-10 11:09:22 -05:00
}
2020-10-28 05:20:05 -05:00
fn is_test ( & self ) -> bool {
2020-10-28 09:09:47 -05:00
matches! ( self , Self ::Test )
2020-10-28 05:20:05 -05:00
}
2020-05-10 11:09:22 -05:00
}
2020-04-25 09:57:59 -05:00
#[ derive(Debug) ]
pub enum DisplaySourceCodeError {
PathNotFound ,
2020-12-12 11:18:19 -06:00
UnknownType ,
2020-04-25 09:57:59 -05:00
}
pub enum HirDisplayError {
/// Errors that can occur when generating source code
DisplaySourceCodeError ( DisplaySourceCodeError ) ,
/// `FmtError` is required to be compatible with std::fmt::Display
FmtError ,
}
impl From < fmt ::Error > for HirDisplayError {
fn from ( _ : fmt ::Error ) -> Self {
Self ::FmtError
}
}
pub struct HirDisplayWrapper < ' a , T > {
db : & ' a dyn HirDatabase ,
t : & ' a T ,
max_size : Option < usize > ,
omit_verbose_types : bool ,
display_target : DisplayTarget ,
}
2019-03-14 16:03:39 -05:00
2020-03-13 10:05:46 -05:00
impl < ' a , T > fmt ::Display for HirDisplayWrapper < ' a , T >
2019-03-14 16:03:39 -05:00
where
T : HirDisplay ,
{
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
2020-04-25 09:57:59 -05:00
match self . t . hir_fmt ( & mut HirFormatter {
db : self . db ,
2019-11-18 11:02:28 -06:00
fmt : f ,
buf : String ::with_capacity ( 20 ) ,
curr_size : 0 ,
2020-04-25 09:57:59 -05:00
max_size : self . max_size ,
omit_verbose_types : self . omit_verbose_types ,
display_target : self . display_target ,
} ) {
Ok ( ( ) ) = > Ok ( ( ) ) ,
Err ( HirDisplayError ::FmtError ) = > Err ( fmt ::Error ) ,
Err ( HirDisplayError ::DisplaySourceCodeError ( _ ) ) = > {
// This should never happen
panic! ( " HirDisplay failed when calling Display::fmt! " )
}
}
2019-03-14 16:03:39 -05:00
}
}
2020-02-14 08:01:25 -06:00
const TYPE_HINT_TRUNCATION : & str = " … " ;
2021-03-14 07:03:39 -05:00
impl < T : HirDisplay > HirDisplay for & '_ T {
2020-04-25 09:57:59 -05:00
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
2020-02-14 08:01:25 -06:00
HirDisplay ::hir_fmt ( * self , f )
}
}
2021-02-28 12:13:37 -06:00
impl HirDisplay for ProjectionTy {
2020-04-25 09:57:59 -05:00
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
2020-02-14 08:01:25 -06:00
if f . should_truncate ( ) {
return write! ( f , " {} " , TYPE_HINT_TRUNCATION ) ;
}
2021-02-28 12:13:37 -06:00
let trait_ = f . db . trait_data ( self . trait_ ( f . db ) ) ;
2021-03-14 10:26:12 -05:00
let first_parameter = self . substitution [ 0 ] . into_displayable (
2021-02-28 12:13:37 -06:00
f . db ,
f . max_size ,
f . omit_verbose_types ,
f . display_target ,
) ;
write! ( f , " <{} as {} " , first_parameter , trait_ . name ) ? ;
2021-03-14 10:26:12 -05:00
if self . substitution . len ( ) > 1 {
2021-02-28 12:13:37 -06:00
write! ( f , " < " ) ? ;
2021-03-14 10:26:12 -05:00
f . write_joined ( & self . substitution [ 1 .. ] , " , " ) ? ;
2021-02-28 12:13:37 -06:00
write! ( f , " > " ) ? ;
}
2021-03-14 10:26:12 -05:00
write! ( f , " >::{} " , f . db . type_alias_data ( from_assoc_type_id ( self . associated_ty_id ) ) . name ) ? ;
2021-02-28 12:13:37 -06:00
Ok ( ( ) )
}
}
impl HirDisplay for Ty {
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
if f . should_truncate ( ) {
return write! ( f , " {} " , TYPE_HINT_TRUNCATION ) ;
}
2021-03-13 07:44:51 -06:00
match self . interned ( & Interner ) {
TyKind ::Never = > write! ( f , " ! " ) ? ,
TyKind ::Str = > write! ( f , " str " ) ? ,
TyKind ::Scalar ( Scalar ::Bool ) = > write! ( f , " bool " ) ? ,
TyKind ::Scalar ( Scalar ::Char ) = > write! ( f , " char " ) ? ,
& TyKind ::Scalar ( Scalar ::Float ( t ) ) = > write! ( f , " {} " , primitive ::float_ty_to_string ( t ) ) ? ,
& TyKind ::Scalar ( Scalar ::Int ( t ) ) = > write! ( f , " {} " , primitive ::int_ty_to_string ( t ) ) ? ,
& TyKind ::Scalar ( Scalar ::Uint ( t ) ) = > write! ( f , " {} " , primitive ::uint_ty_to_string ( t ) ) ? ,
2021-03-14 11:40:55 -05:00
TyKind ::Slice ( t ) = > {
2020-10-28 11:58:16 -05:00
write! ( f , " [ " ) ? ;
t . hir_fmt ( f ) ? ;
write! ( f , " ] " ) ? ;
2020-02-14 08:01:25 -06:00
}
2021-03-14 11:40:55 -05:00
TyKind ::Array ( t ) = > {
2020-10-28 11:58:16 -05:00
write! ( f , " [ " ) ? ;
t . hir_fmt ( f ) ? ;
write! ( f , " ; _] " ) ? ;
2020-02-14 08:01:25 -06:00
}
2021-03-14 11:40:55 -05:00
TyKind ::Raw ( m , t ) | TyKind ::Ref ( m , t ) = > {
2021-01-12 13:19:13 -06:00
let ty_display =
t . into_displayable ( f . db , f . max_size , f . omit_verbose_types , f . display_target ) ;
2020-10-06 07:40:27 -05:00
2021-03-13 07:44:51 -06:00
if matches! ( self . interned ( & Interner ) , TyKind ::Raw ( .. ) ) {
2021-03-01 12:30:34 -06:00
write! (
f ,
" *{} " ,
match m {
Mutability ::Not = > " const " ,
Mutability ::Mut = > " mut " ,
}
) ? ;
2020-10-06 07:40:27 -05:00
} else {
2021-03-01 12:30:34 -06:00
write! (
f ,
" &{} " ,
match m {
Mutability ::Not = > " " ,
Mutability ::Mut = > " mut " ,
}
) ? ;
2021-01-12 13:19:13 -06:00
}
2021-03-13 13:05:47 -06:00
// FIXME: all this just to decide whether to use parentheses...
2021-01-12 13:19:13 -06:00
let datas ;
2021-03-13 07:44:51 -06:00
let predicates = match t . interned ( & Interner ) {
TyKind ::Dyn ( predicates ) if predicates . len ( ) > 1 = > {
2021-01-12 13:19:13 -06:00
Cow ::Borrowed ( predicates . as_ref ( ) )
}
2021-03-14 10:33:27 -05:00
& TyKind ::Alias ( AliasTy ::Opaque ( OpaqueTy {
opaque_ty_id ,
substitution : ref parameters ,
} ) ) = > {
2021-03-13 13:05:47 -06:00
let impl_trait_id = f . db . lookup_intern_impl_trait_id ( opaque_ty_id . into ( ) ) ;
if let ImplTraitId ::ReturnTypeImplTrait ( func , idx ) = impl_trait_id {
datas =
f . db . return_type_impl_traits ( func )
. expect ( " impl trait id without data " ) ;
let data = ( * datas )
. as_ref ( )
. map ( | rpit | rpit . impl_traits [ idx as usize ] . bounds . clone ( ) ) ;
let bounds = data . subst ( parameters ) ;
Cow ::Owned ( bounds . value )
} else {
Cow ::Borrowed ( & [ ] [ .. ] )
}
2021-01-12 13:19:13 -06:00
}
_ = > Cow ::Borrowed ( & [ ] [ .. ] ) ,
} ;
if let [ GenericPredicate ::Implemented ( trait_ref ) , _ ] = predicates . as_ref ( ) {
let trait_ = trait_ref . trait_ ;
if fn_traits ( f . db . upcast ( ) , trait_ ) . any ( | it | it = = trait_ ) {
return write! ( f , " {} " , ty_display ) ;
}
2020-10-06 07:40:27 -05:00
}
2021-01-12 13:19:13 -06:00
if predicates . len ( ) > 1 {
2020-10-06 07:40:27 -05:00
write! ( f , " ( " ) ? ;
write! ( f , " {} " , ty_display ) ? ;
write! ( f , " ) " ) ? ;
} else {
write! ( f , " {} " , ty_display ) ? ;
}
2020-02-14 08:01:25 -06:00
}
2021-03-13 07:44:51 -06:00
TyKind ::Tuple ( _ , substs ) = > {
2021-02-28 12:13:37 -06:00
if substs . len ( ) = = 1 {
2020-10-28 11:58:16 -05:00
write! ( f , " ( " ) ? ;
2021-02-28 12:13:37 -06:00
substs [ 0 ] . hir_fmt ( f ) ? ;
2020-10-28 11:58:16 -05:00
write! ( f , " ,) " ) ? ;
2020-02-14 08:01:25 -06:00
} else {
write! ( f , " ( " ) ? ;
2021-02-28 12:13:37 -06:00
f . write_joined ( & * substs . 0 , " , " ) ? ;
2020-02-14 08:01:25 -06:00
write! ( f , " ) " ) ? ;
}
}
2021-03-13 07:44:51 -06:00
TyKind ::Function ( fn_ptr ) = > {
2021-02-28 15:12:07 -06:00
let sig = CallableSig ::from_fn_ptr ( fn_ptr ) ;
2020-12-09 11:06:56 -06:00
sig . hir_fmt ( f ) ? ;
2020-02-14 08:01:25 -06:00
}
2021-03-13 07:44:51 -06:00
TyKind ::FnDef ( def , parameters ) = > {
2021-03-13 10:55:50 -06:00
let def = from_chalk ( f . db , * def ) ;
2021-02-28 12:13:37 -06:00
let sig = f . db . callable_item_signature ( def ) . subst ( parameters ) ;
2020-03-28 16:25:29 -05:00
match def {
2020-07-16 06:15:00 -05:00
CallableDefId ::FunctionId ( ff ) = > {
write! ( f , " fn {} " , f . db . function_data ( ff ) . name ) ?
}
CallableDefId ::StructId ( s ) = > write! ( f , " {} " , f . db . struct_data ( s ) . name ) ? ,
CallableDefId ::EnumVariantId ( e ) = > {
2020-03-28 16:25:29 -05:00
write! ( f , " {} " , f . db . enum_data ( e . parent ) . variants [ e . local_id ] . name ) ?
2020-02-14 08:01:25 -06:00
}
} ;
2021-02-28 12:13:37 -06:00
if parameters . len ( ) > 0 {
2020-03-13 10:05:46 -05:00
let generics = generics ( f . db . upcast ( ) , def . into ( ) ) ;
2020-02-14 08:01:25 -06:00
let ( parent_params , self_param , type_params , _impl_trait_params ) =
generics . provenance_split ( ) ;
let total_len = parent_params + self_param + type_params ;
// We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
if total_len > 0 {
write! ( f , " < " ) ? ;
2021-02-28 12:13:37 -06:00
f . write_joined ( & parameters . 0 [ .. total_len ] , " , " ) ? ;
2020-02-14 08:01:25 -06:00
write! ( f , " > " ) ? ;
}
}
write! ( f , " ( " ) ? ;
f . write_joined ( sig . params ( ) , " , " ) ? ;
2020-04-05 10:25:47 -05:00
write! ( f , " ) " ) ? ;
let ret = sig . ret ( ) ;
if * ret ! = Ty ::unit ( ) {
2020-10-28 11:58:16 -05:00
let ret_display = ret . into_displayable (
f . db ,
f . max_size ,
f . omit_verbose_types ,
f . display_target ,
) ;
2020-07-20 15:50:41 -05:00
write! ( f , " -> {} " , ret_display ) ? ;
2020-04-05 10:25:47 -05:00
}
2020-02-14 08:01:25 -06:00
}
2021-03-13 07:44:51 -06:00
TyKind ::Adt ( AdtId ( def_id ) , parameters ) = > {
2020-04-25 09:57:59 -05:00
match f . display_target {
2020-10-28 09:09:47 -05:00
DisplayTarget ::Diagnostics | DisplayTarget ::Test = > {
2021-02-28 12:46:59 -06:00
let name = match * def_id {
2021-03-01 14:57:39 -06:00
hir_def ::AdtId ::StructId ( it ) = > f . db . struct_data ( it ) . name . clone ( ) ,
hir_def ::AdtId ::UnionId ( it ) = > f . db . union_data ( it ) . name . clone ( ) ,
hir_def ::AdtId ::EnumId ( it ) = > f . db . enum_data ( it ) . name . clone ( ) ,
2020-04-25 09:57:59 -05:00
} ;
write! ( f , " {} " , name ) ? ;
}
2020-10-28 09:09:47 -05:00
DisplayTarget ::SourceCode { module_id } = > {
2020-10-28 05:20:05 -05:00
if let Some ( path ) = find_path ::find_path (
f . db . upcast ( ) ,
2021-02-28 12:46:59 -06:00
ItemInNs ::Types ( ( * def_id ) . into ( ) ) ,
2020-10-28 05:20:05 -05:00
module_id ,
) {
write! ( f , " {} " , path ) ? ;
} else {
return Err ( HirDisplayError ::DisplaySourceCodeError (
DisplaySourceCodeError ::PathNotFound ,
) ) ;
}
}
2020-04-25 09:57:59 -05:00
}
2021-02-28 12:13:37 -06:00
if parameters . len ( ) > 0 {
2021-03-13 07:44:51 -06:00
let parameters_to_write = if f . display_target . is_source_code ( )
| | f . omit_verbose_types ( )
{
match self
2021-03-13 10:55:50 -06:00
. as_generic_def ( f . db )
2021-03-13 07:44:51 -06:00
. map ( | generic_def_id | f . db . generic_defaults ( generic_def_id ) )
. filter ( | defaults | ! defaults . is_empty ( ) )
{
None = > parameters . 0. as_ref ( ) ,
Some ( default_parameters ) = > {
let mut default_from = 0 ;
for ( i , parameter ) in parameters . iter ( ) . enumerate ( ) {
match ( parameter . interned ( & Interner ) , default_parameters . get ( i ) )
{
( & TyKind ::Unknown , _ ) | ( _ , None ) = > {
default_from = i + 1 ;
}
( _ , Some ( default_parameter ) ) = > {
let actual_default = default_parameter
. clone ( )
. subst ( & parameters . prefix ( i ) ) ;
if parameter ! = & actual_default {
2020-06-26 09:36:59 -05:00
default_from = i + 1 ;
2020-05-10 11:09:22 -05:00
}
2020-02-14 08:01:25 -06:00
}
}
}
2021-03-13 07:44:51 -06:00
& parameters . 0 [ 0 .. default_from ]
2020-02-14 08:01:25 -06:00
}
2021-03-13 07:44:51 -06:00
}
} else {
parameters . 0. as_ref ( )
} ;
2020-05-10 11:09:22 -05:00
if ! parameters_to_write . is_empty ( ) {
write! ( f , " < " ) ? ;
f . write_joined ( parameters_to_write , " , " ) ? ;
write! ( f , " > " ) ? ;
}
2020-02-14 08:01:25 -06:00
}
}
2021-03-13 10:36:07 -06:00
TyKind ::AssociatedType ( assoc_type_id , parameters ) = > {
let type_alias = from_assoc_type_id ( * assoc_type_id ) ;
2020-03-13 10:05:46 -05:00
let trait_ = match type_alias . lookup ( f . db . upcast ( ) ) . container {
2020-02-14 08:01:25 -06:00
AssocContainerId ::TraitId ( it ) = > it ,
_ = > panic! ( " not an associated type " ) ,
} ;
2020-03-31 11:00:23 -05:00
let trait_ = f . db . trait_data ( trait_ ) ;
2021-03-13 10:36:07 -06:00
let type_alias_data = f . db . type_alias_data ( type_alias ) ;
2020-10-27 14:23:09 -05:00
2020-10-28 05:20:05 -05:00
// Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
2020-10-28 09:09:47 -05:00
if f . display_target . is_test ( ) {
write! ( f , " {}::{} " , trait_ . name , type_alias_data . name ) ? ;
2021-02-28 12:13:37 -06:00
if parameters . len ( ) > 0 {
2020-10-27 14:23:09 -05:00
write! ( f , " < " ) ? ;
2021-02-28 12:13:37 -06:00
f . write_joined ( & * parameters . 0 , " , " ) ? ;
2020-10-27 14:23:09 -05:00
write! ( f , " > " ) ? ;
}
} else {
2021-03-13 10:36:07 -06:00
let projection_ty = ProjectionTy {
2021-03-14 10:26:12 -05:00
associated_ty_id : to_assoc_type_id ( type_alias ) ,
substitution : parameters . clone ( ) ,
2021-03-13 10:36:07 -06:00
} ;
2020-10-28 09:09:47 -05:00
projection_ty . hir_fmt ( f ) ? ;
2020-02-14 08:01:25 -06:00
}
}
2021-03-13 07:44:51 -06:00
TyKind ::ForeignType ( type_alias ) = > {
2021-03-13 10:23:19 -06:00
let type_alias = f . db . type_alias_data ( from_foreign_def_id ( * type_alias ) ) ;
2020-09-12 21:24:19 -05:00
write! ( f , " {} " , type_alias . name ) ? ;
}
2021-03-13 07:44:51 -06:00
TyKind ::OpaqueType ( opaque_ty_id , parameters ) = > {
2021-03-13 13:05:47 -06:00
let impl_trait_id = f . db . lookup_intern_impl_trait_id ( ( * opaque_ty_id ) . into ( ) ) ;
match impl_trait_id {
ImplTraitId ::ReturnTypeImplTrait ( func , idx ) = > {
2020-03-04 16:00:44 -06:00
let datas =
f . db . return_type_impl_traits ( func ) . expect ( " impl trait id without data " ) ;
let data = ( * datas )
. as_ref ( )
. map ( | rpit | rpit . impl_traits [ idx as usize ] . bounds . clone ( ) ) ;
2021-02-28 12:13:37 -06:00
let bounds = data . subst ( & parameters ) ;
2021-02-20 13:43:04 -06:00
write_bounds_like_dyn_trait_with_prefix ( " impl " , & bounds . value , f ) ? ;
2020-09-10 07:01:23 -05:00
// FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
2020-03-04 16:00:44 -06:00
}
2021-03-13 13:05:47 -06:00
ImplTraitId ::AsyncBlockTypeImplTrait ( .. ) = > {
2020-09-10 07:01:23 -05:00
write! ( f , " impl Future<Output = " ) ? ;
2021-02-28 12:13:37 -06:00
parameters [ 0 ] . hir_fmt ( f ) ? ;
2020-09-10 07:01:23 -05:00
write! ( f , " > " ) ? ;
}
}
2020-03-04 16:00:44 -06:00
}
2021-03-13 07:44:51 -06:00
TyKind ::Closure ( .. , substs ) = > {
2021-02-28 12:13:37 -06:00
let sig = substs [ 0 ] . callable_sig ( f . db ) ;
2020-03-27 12:56:18 -05:00
if let Some ( sig ) = sig {
if sig . params ( ) . is_empty ( ) {
write! ( f , " || " ) ? ;
} else if f . omit_verbose_types ( ) {
write! ( f , " |{}| " , TYPE_HINT_TRUNCATION ) ? ;
} else {
write! ( f , " | " ) ? ;
f . write_joined ( sig . params ( ) , " , " ) ? ;
write! ( f , " | " ) ? ;
} ;
2020-07-20 15:50:41 -05:00
2020-10-28 11:58:16 -05:00
let ret_display = sig . ret ( ) . into_displayable (
f . db ,
f . max_size ,
f . omit_verbose_types ,
f . display_target ,
) ;
2020-07-20 15:50:41 -05:00
write! ( f , " -> {} " , ret_display ) ? ;
2020-02-14 08:01:25 -06:00
} else {
2020-03-27 12:56:18 -05:00
write! ( f , " {{closure}} " ) ? ;
}
2020-02-14 08:01:25 -06:00
}
2021-03-13 12:47:34 -06:00
TyKind ::Placeholder ( idx ) = > {
let id = from_placeholder_idx ( f . db , * idx ) ;
2020-03-13 10:05:46 -05:00
let generics = generics ( f . db . upcast ( ) , id . parent ) ;
2020-02-14 08:01:25 -06:00
let param_data = & generics . params . types [ id . local_id ] ;
match param_data . provenance {
TypeParamProvenance ::TypeParamList | TypeParamProvenance ::TraitSelf = > {
write! ( f , " {} " , param_data . name . clone ( ) . unwrap_or_else ( Name ::missing ) ) ?
}
TypeParamProvenance ::ArgumentImplTrait = > {
2021-03-13 12:47:34 -06:00
let bounds = f . db . generic_predicates_for_param ( id ) ;
2021-03-15 15:02:34 -05:00
let substs = Substitution ::type_params_for_generics ( f . db , & generics ) ;
2021-02-20 13:43:04 -06:00
write_bounds_like_dyn_trait_with_prefix (
" impl " ,
2020-02-14 08:01:25 -06:00
& bounds . iter ( ) . map ( | b | b . clone ( ) . subst ( & substs ) ) . collect ::< Vec < _ > > ( ) ,
f ,
) ? ;
}
}
}
2021-03-13 07:44:51 -06:00
TyKind ::BoundVar ( idx ) = > write! ( f , " ?{}.{} " , idx . debruijn . depth ( ) , idx . index ) ? ,
TyKind ::Dyn ( predicates ) = > {
2021-02-20 13:43:04 -06:00
write_bounds_like_dyn_trait_with_prefix ( " dyn " , predicates , f ) ? ;
2020-02-14 08:01:25 -06:00
}
2021-03-13 07:44:51 -06:00
TyKind ::Alias ( AliasTy ::Projection ( p_ty ) ) = > p_ty . hir_fmt ( f ) ? ,
TyKind ::Alias ( AliasTy ::Opaque ( opaque_ty ) ) = > {
2021-03-13 13:05:47 -06:00
let impl_trait_id = f . db . lookup_intern_impl_trait_id ( opaque_ty . opaque_ty_id . into ( ) ) ;
match impl_trait_id {
ImplTraitId ::ReturnTypeImplTrait ( func , idx ) = > {
2020-03-04 16:00:44 -06:00
let datas =
f . db . return_type_impl_traits ( func ) . expect ( " impl trait id without data " ) ;
let data = ( * datas )
. as_ref ( )
. map ( | rpit | rpit . impl_traits [ idx as usize ] . bounds . clone ( ) ) ;
2021-03-14 10:33:27 -05:00
let bounds = data . subst ( & opaque_ty . substitution ) ;
2021-02-20 13:43:04 -06:00
write_bounds_like_dyn_trait_with_prefix ( " impl " , & bounds . value , f ) ? ;
2020-09-10 07:01:23 -05:00
}
2021-03-13 13:05:47 -06:00
ImplTraitId ::AsyncBlockTypeImplTrait ( .. ) = > {
2020-09-10 07:01:23 -05:00
write! ( f , " {{async block}} " ) ? ;
2020-03-04 16:00:44 -06:00
}
} ;
}
2021-03-13 07:44:51 -06:00
TyKind ::Unknown = > {
2020-12-12 11:18:19 -06:00
if f . display_target . is_source_code ( ) {
return Err ( HirDisplayError ::DisplaySourceCodeError (
DisplaySourceCodeError ::UnknownType ,
) ) ;
}
write! ( f , " {{unknown}} " ) ? ;
}
2021-03-13 07:44:51 -06:00
TyKind ::InferenceVar ( .. ) = > write! ( f , " _ " ) ? ,
2020-02-14 08:01:25 -06:00
}
Ok ( ( ) )
}
}
2021-02-28 15:12:07 -06:00
impl HirDisplay for CallableSig {
2020-12-09 11:06:56 -06:00
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
write! ( f , " fn( " ) ? ;
f . write_joined ( self . params ( ) , " , " ) ? ;
if self . is_varargs {
if self . params ( ) . is_empty ( ) {
write! ( f , " ... " ) ? ;
} else {
write! ( f , " , ... " ) ? ;
}
}
write! ( f , " ) " ) ? ;
let ret = self . ret ( ) ;
if * ret ! = Ty ::unit ( ) {
let ret_display =
ret . into_displayable ( f . db , f . max_size , f . omit_verbose_types , f . display_target ) ;
write! ( f , " -> {} " , ret_display ) ? ;
}
Ok ( ( ) )
}
}
2021-01-12 13:19:13 -06:00
fn fn_traits ( db : & dyn DefDatabase , trait_ : TraitId ) -> impl Iterator < Item = TraitId > {
2021-03-09 12:09:02 -06:00
let krate = trait_ . lookup ( db ) . container . krate ( ) ;
2021-01-12 13:19:13 -06:00
let fn_traits = [
db . lang_item ( krate , " fn " . into ( ) ) ,
db . lang_item ( krate , " fn_mut " . into ( ) ) ,
db . lang_item ( krate , " fn_once " . into ( ) ) ,
] ;
// FIXME: Replace ArrayVec when into_iter is a thing on arrays
ArrayVec ::from ( fn_traits ) . into_iter ( ) . flatten ( ) . flat_map ( | it | it . as_trait ( ) )
}
2021-02-20 13:43:04 -06:00
pub fn write_bounds_like_dyn_trait_with_prefix (
prefix : & str ,
predicates : & [ GenericPredicate ] ,
f : & mut HirFormatter ,
) -> Result < ( ) , HirDisplayError > {
write! ( f , " {} " , prefix ) ? ;
if ! predicates . is_empty ( ) {
write! ( f , " " ) ? ;
write_bounds_like_dyn_trait ( predicates , f )
} else {
Ok ( ( ) )
}
}
fn write_bounds_like_dyn_trait (
2020-02-14 08:01:25 -06:00
predicates : & [ GenericPredicate ] ,
2020-03-13 10:05:46 -05:00
f : & mut HirFormatter ,
2020-04-25 09:57:59 -05:00
) -> Result < ( ) , HirDisplayError > {
2020-02-14 08:01:25 -06:00
// Note: This code is written to produce nice results (i.e.
// corresponding to surface Rust) for types that can occur in
// actual Rust. It will have weird results if the predicates
// aren't as expected (i.e. self types = $0, projection
// predicates for a certain trait come after the Implemented
// predicate for that trait).
let mut first = true ;
let mut angle_open = false ;
2021-01-12 13:19:13 -06:00
let mut is_fn_trait = false ;
2020-02-14 08:01:25 -06:00
for p in predicates . iter ( ) {
match p {
GenericPredicate ::Implemented ( trait_ref ) = > {
2021-01-12 13:19:13 -06:00
let trait_ = trait_ref . trait_ ;
if ! is_fn_trait {
is_fn_trait = fn_traits ( f . db . upcast ( ) , trait_ ) . any ( | it | it = = trait_ ) ;
}
if ! is_fn_trait & & angle_open {
2020-02-14 08:01:25 -06:00
write! ( f , " > " ) ? ;
2020-08-13 15:13:34 -05:00
angle_open = false ;
2020-02-14 08:01:25 -06:00
}
if ! first {
write! ( f , " + " ) ? ;
}
// We assume that the self type is $0 (i.e. the
// existential) here, which is the only thing that's
// possible in actual Rust, and hence don't print it
2021-01-12 13:19:13 -06:00
write! ( f , " {} " , f . db . trait_data ( trait_ ) . name ) ? ;
if let [ _ , params @ .. ] = & * trait_ref . substs . 0 {
if is_fn_trait {
if let Some ( args ) = params . first ( ) . and_then ( | it | it . as_tuple ( ) ) {
write! ( f , " ( " ) ? ;
f . write_joined ( & * args . 0 , " , " ) ? ;
write! ( f , " ) " ) ? ;
}
} else if ! params . is_empty ( ) {
write! ( f , " < " ) ? ;
f . write_joined ( params , " , " ) ? ;
// there might be assoc type bindings, so we leave the angle brackets open
angle_open = true ;
}
2020-02-14 08:01:25 -06:00
}
}
2021-01-12 13:19:13 -06:00
GenericPredicate ::Projection ( projection_pred ) if is_fn_trait = > {
is_fn_trait = false ;
write! ( f , " -> " ) ? ;
projection_pred . ty . hir_fmt ( f ) ? ;
}
2020-02-14 08:01:25 -06:00
GenericPredicate ::Projection ( projection_pred ) = > {
// in types in actual Rust, these will always come
// after the corresponding Implemented predicate
if angle_open {
write! ( f , " , " ) ? ;
} else {
write! ( f , " < " ) ? ;
angle_open = true ;
}
2021-03-13 10:36:07 -06:00
let type_alias = f . db . type_alias_data ( from_assoc_type_id (
2021-03-14 10:26:12 -05:00
projection_pred . projection_ty . associated_ty_id ,
2021-03-13 10:36:07 -06:00
) ) ;
2020-03-31 11:00:23 -05:00
write! ( f , " {} = " , type_alias . name ) ? ;
2020-02-14 08:01:25 -06:00
projection_pred . ty . hir_fmt ( f ) ? ;
}
GenericPredicate ::Error = > {
if angle_open {
// impl Trait<X, {error}>
write! ( f , " , " ) ? ;
} else if ! first {
// impl Trait + {error}
write! ( f , " + " ) ? ;
}
p . hir_fmt ( f ) ? ;
}
}
first = false ;
}
if angle_open {
write! ( f , " > " ) ? ;
}
Ok ( ( ) )
}
impl TraitRef {
2020-04-25 09:57:59 -05:00
fn hir_fmt_ext ( & self , f : & mut HirFormatter , use_as : bool ) -> Result < ( ) , HirDisplayError > {
2020-02-14 08:01:25 -06:00
if f . should_truncate ( ) {
return write! ( f , " {} " , TYPE_HINT_TRUNCATION ) ;
}
self . substs [ 0 ] . hir_fmt ( f ) ? ;
if use_as {
write! ( f , " as " ) ? ;
} else {
write! ( f , " : " ) ? ;
}
2020-03-31 11:00:23 -05:00
write! ( f , " {} " , f . db . trait_data ( self . trait_ ) . name ) ? ;
2020-02-14 08:01:25 -06:00
if self . substs . len ( ) > 1 {
write! ( f , " < " ) ? ;
f . write_joined ( & self . substs [ 1 .. ] , " , " ) ? ;
write! ( f , " > " ) ? ;
}
Ok ( ( ) )
}
}
impl HirDisplay for TraitRef {
2020-04-25 09:57:59 -05:00
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
2020-02-14 08:01:25 -06:00
self . hir_fmt_ext ( f , false )
}
}
impl HirDisplay for GenericPredicate {
2020-04-25 09:57:59 -05:00
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
2020-02-14 08:01:25 -06:00
if f . should_truncate ( ) {
return write! ( f , " {} " , TYPE_HINT_TRUNCATION ) ;
}
match self {
GenericPredicate ::Implemented ( trait_ref ) = > trait_ref . hir_fmt ( f ) ? ,
GenericPredicate ::Projection ( projection_pred ) = > {
write! ( f , " < " ) ? ;
projection_pred . projection_ty . trait_ref ( f . db ) . hir_fmt_ext ( f , true ) ? ;
write! (
f ,
2020-10-28 11:58:16 -05:00
" >::{} = " ,
2021-03-13 10:36:07 -06:00
f . db . type_alias_data ( from_assoc_type_id (
2021-03-14 10:26:12 -05:00
projection_pred . projection_ty . associated_ty_id
2021-03-13 10:36:07 -06:00
) )
. name ,
2020-02-14 08:01:25 -06:00
) ? ;
2020-10-28 11:58:16 -05:00
projection_pred . ty . hir_fmt ( f ) ? ;
2020-02-14 08:01:25 -06:00
}
GenericPredicate ::Error = > write! ( f , " {{error}} " ) ? ,
}
Ok ( ( ) )
}
}
2020-12-11 06:49:32 -06:00
impl HirDisplay for Lifetime {
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
match self {
Lifetime ::Parameter ( id ) = > {
let generics = generics ( f . db . upcast ( ) , id . parent ) ;
let param_data = & generics . params . lifetimes [ id . local_id ] ;
write! ( f , " {} " , & param_data . name )
}
Lifetime ::Static = > write! ( f , " 'static " ) ,
}
}
}
2020-02-14 08:01:25 -06:00
impl HirDisplay for Obligation {
2020-04-25 09:57:59 -05:00
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
2020-10-06 07:40:27 -05:00
match self {
2020-10-28 11:58:16 -05:00
Obligation ::Trait ( tr ) = > {
write! ( f , " Implements( " ) ? ;
tr . hir_fmt ( f ) ? ;
write! ( f , " ) " )
}
Obligation ::Projection ( proj ) = > {
write! ( f , " Normalize( " ) ? ;
proj . projection_ty . hir_fmt ( f ) ? ;
write! ( f , " => " ) ? ;
proj . ty . hir_fmt ( f ) ? ;
write! ( f , " ) " )
}
2020-10-06 07:40:27 -05:00
}
2020-02-14 08:01:25 -06:00
}
}
2021-03-14 07:03:39 -05:00
pub fn write_visibility (
module_id : ModuleId ,
vis : Visibility ,
f : & mut HirFormatter ,
) -> Result < ( ) , HirDisplayError > {
match vis {
Visibility ::Public = > write! ( f , " pub " ) ,
Visibility ::Module ( vis_id ) = > {
let def_map = module_id . def_map ( f . db . upcast ( ) ) ;
let root_module_id = def_map . module_id ( def_map . root ( ) ) ;
if vis_id = = module_id {
// pub(self) or omitted
Ok ( ( ) )
} else if root_module_id = = vis_id {
write! ( f , " pub(crate) " )
} else if module_id . containing_module ( f . db . upcast ( ) ) = = Some ( vis_id ) {
write! ( f , " pub(super) " )
} else {
write! ( f , " pub(in ...) " )
}
}
}
}
impl HirDisplay for TypeRef {
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
match self {
TypeRef ::Never = > write! ( f , " ! " ) ? ,
TypeRef ::Placeholder = > write! ( f , " _ " ) ? ,
TypeRef ::Tuple ( elems ) = > {
write! ( f , " ( " ) ? ;
f . write_joined ( elems , " , " ) ? ;
if elems . len ( ) = = 1 {
write! ( f , " , " ) ? ;
}
write! ( f , " ) " ) ? ;
}
TypeRef ::Path ( path ) = > path . hir_fmt ( f ) ? ,
TypeRef ::RawPtr ( inner , mutability ) = > {
let mutability = match mutability {
hir_def ::type_ref ::Mutability ::Shared = > " *const " ,
hir_def ::type_ref ::Mutability ::Mut = > " *mut " ,
} ;
write! ( f , " {} " , mutability ) ? ;
inner . hir_fmt ( f ) ? ;
}
TypeRef ::Reference ( inner , lifetime , mutability ) = > {
let mutability = match mutability {
hir_def ::type_ref ::Mutability ::Shared = > " " ,
hir_def ::type_ref ::Mutability ::Mut = > " mut " ,
} ;
write! ( f , " & " ) ? ;
if let Some ( lifetime ) = lifetime {
write! ( f , " {} " , lifetime . name ) ? ;
}
write! ( f , " {} " , mutability ) ? ;
inner . hir_fmt ( f ) ? ;
}
TypeRef ::Array ( inner ) = > {
write! ( f , " [ " ) ? ;
inner . hir_fmt ( f ) ? ;
// FIXME: Array length?
write! ( f , " ; _] " ) ? ;
}
TypeRef ::Slice ( inner ) = > {
write! ( f , " [ " ) ? ;
inner . hir_fmt ( f ) ? ;
write! ( f , " ] " ) ? ;
}
TypeRef ::Fn ( tys , is_varargs ) = > {
// FIXME: Function pointer qualifiers.
write! ( f , " fn( " ) ? ;
f . write_joined ( & tys [ .. tys . len ( ) - 1 ] , " , " ) ? ;
if * is_varargs {
write! ( f , " {}... " , if tys . len ( ) = = 1 { " " } else { " , " } ) ? ;
}
write! ( f , " ) " ) ? ;
let ret_ty = tys . last ( ) . unwrap ( ) ;
match ret_ty {
TypeRef ::Tuple ( tup ) if tup . is_empty ( ) = > { }
_ = > {
write! ( f , " -> " ) ? ;
ret_ty . hir_fmt ( f ) ? ;
}
}
}
TypeRef ::ImplTrait ( bounds ) = > {
write! ( f , " impl " ) ? ;
f . write_joined ( bounds , " + " ) ? ;
}
TypeRef ::DynTrait ( bounds ) = > {
write! ( f , " dyn " ) ? ;
f . write_joined ( bounds , " + " ) ? ;
}
TypeRef ::Error = > write! ( f , " {{error}} " ) ? ,
}
Ok ( ( ) )
}
}
impl HirDisplay for TypeBound {
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
match self {
TypeBound ::Path ( path ) = > path . hir_fmt ( f ) ,
TypeBound ::Lifetime ( lifetime ) = > write! ( f , " {} " , lifetime . name ) ,
TypeBound ::Error = > write! ( f , " {{error}} " ) ,
}
}
}
impl HirDisplay for Path {
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
match ( self . type_anchor ( ) , self . kind ( ) ) {
( Some ( anchor ) , _ ) = > {
write! ( f , " < " ) ? ;
anchor . hir_fmt ( f ) ? ;
write! ( f , " > " ) ? ;
}
( _ , PathKind ::Plain ) = > { }
( _ , PathKind ::Abs ) = > write! ( f , " :: " ) ? ,
( _ , PathKind ::Crate ) = > write! ( f , " crate " ) ? ,
( _ , PathKind ::Super ( 0 ) ) = > write! ( f , " self " ) ? ,
( _ , PathKind ::Super ( n ) ) = > {
write! ( f , " super " ) ? ;
for _ in 0 .. * n {
write! ( f , " ::super " ) ? ;
}
}
( _ , PathKind ::DollarCrate ( _ ) ) = > write! ( f , " {{extern_crate}} " ) ? ,
}
for ( seg_idx , segment ) in self . segments ( ) . iter ( ) . enumerate ( ) {
if seg_idx ! = 0 {
write! ( f , " :: " ) ? ;
}
write! ( f , " {} " , segment . name ) ? ;
if let Some ( generic_args ) = segment . args_and_bindings {
// We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`.
// Do we actually format expressions?
write! ( f , " < " ) ? ;
let mut first = true ;
for arg in & generic_args . args {
if first {
first = false ;
if generic_args . has_self_type {
// FIXME: Convert to `<Ty as Trait>` form.
write! ( f , " Self = " ) ? ;
}
} else {
write! ( f , " , " ) ? ;
}
arg . hir_fmt ( f ) ? ;
}
for binding in & generic_args . bindings {
if first {
first = false ;
} else {
write! ( f , " , " ) ? ;
}
write! ( f , " {} " , binding . name ) ? ;
match & binding . type_ref {
Some ( ty ) = > {
write! ( f , " = " ) ? ;
ty . hir_fmt ( f ) ?
}
None = > {
write! ( f , " : " ) ? ;
f . write_joined ( & binding . bounds , " + " ) ? ;
}
}
}
write! ( f , " > " ) ? ;
}
}
Ok ( ( ) )
}
}
impl HirDisplay for GenericArg {
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
match self {
GenericArg ::Type ( ty ) = > ty . hir_fmt ( f ) ,
GenericArg ::Lifetime ( lifetime ) = > write! ( f , " {} " , lifetime . name ) ,
}
}
}